三种实现 AJAX 的方法以及 Vue 和 axios 结合使用的坑

本贴最后更新于 2142 天前,其中的信息可能已经东海扬尘

前言

之前曾经想自己写一个天气的 App,并找到了一个免费的天气数据接口的服务商——和风天气,当时也不懂怎么发 HTTP 请求,而且也只会用 Java 语言,看到官方文档里面有一个 Java 代码示例,就复制了一下在自己电脑上调通。一开始是在控制台输出天气数据的,后来用 Swing 写了一个图形化界面并放置数据,但也就到此为止了,并没有什么实用价值。

最近学习了一下前端的相关知识,发现像和风天气这样的数据接口,根本不需要用到像 Java 这样的大型语言,只需在网页端用 Javascript 发 HTTP 请求就能获得 JSON 数据,之后再渲染到 HTML 网页,大大节省了资源利用和开发时间,并了解到开发这样的网页最适合的方式就是使用 AJAX,因为它可以实现网页的局部更新。这样我就可以实现如下的业务场景:输入想要搜索的城市,点击搜索,下面显示出该城市的天气信息,而不影响页面的其他内容。有时候 JS 调用 AJAX 请求会有跨域问题,但和风天气的数据接口并没有这个问题。

具体场景

界面如图:

界面

在输入框输入城市名,点击搜索按钮,可以在下面显示出各项数据(从接口获得)。

大致的 HTML 代码如下:

<div class="container "> <div class="text-center"> <h1>天气查询</h1> <div class="form-inline row"> <input type="text" class="form-control" placeholder="关键字" id="input-location"/> <button class="btn btn-primary" onclick="loadBasic();loadAir();">搜 索</button> </div> </div> <table class="table" > <thead> <tr> <th>位置</th> <th>温度</th> <th>湿度</th> <th>能见度</th> <th>空气质量指数</th> <th>更新时间</th> </tr> </thead> <tbody> <tr> <td id="loc"></td> <td id="tmp"></td> <td id="hum"></td> <td id="vis"></td> <td id="aqi"></td> <td id="update"></td> </tr> </tbody> </table> </div>

和风天气返回的 json 数据示例

{ "HeWeather6": [{ "basic": { "cid": "CN101010100", "location": "北京", "parent_city": "北京", "admin_area": "北京", "cnty": "中国", "lat": "39.90498734", "lon": "116.4052887", "tz": "+8.00" }, "update": { "loc": "2019-06-05 21:57", "utc": "2019-06-05 13:57" }, "status": "ok", "now": { "cloud": "91", "cond_code": "104", "cond_txt": "阴", "fl": "23", "hum": "55", "pcpn": "0.0", "pres": "1005", "tmp": "23", "vis": "16", "wind_deg": "249", "wind_dir": "西南风", "wind_sc": "2", "wind_spd": "7" } }] }

下面主要描述三种我自己探索经历中使用 AJAX 的方法

传统 AJAX

原生 JS 就支持 AJAX,这里我借鉴了一部分网上的教程里的代码,具体的代码如下:

function loadBasic() //获取基本天气信息 { var xmlhttp; if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest(); } else {// code for IE6, IE5 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { var str=xmlhttp.responseText; var obj=JSON.parse(str); document.getElementById("loc").innerHTML=obj.HeWeather6[0].basic.location; document.getElementById("tmp").innerHTML=obj.HeWeather6[0].now.tmp; document.getElementById("hum").innerHTML=obj.HeWeather6[0].now.hum+"%"; document.getElementById("vis").innerHTML=obj.HeWeather6[0].now.vis+"km"; } } var location=document.getElementById("input-location").value; xmlhttp.open("GET","https://free-api.heweather.net/s6/weather/now?location="+location+"&key=我的和风天气key",true); xmlhttp.send(); } function loadAir() //获取空气质量信息 { //仿照上面的方法 }

原生 AJAX 的确能够满足业务场景的要求,但操作较为繁琐,于是我又找到了另一种方法——axios

axios

axios 是对原生 AJAX 的封装,使用时需要导入 axios.js 文件包。相较于原生 JS,axios 使用起来更为简便,同样的功能代码如下:

function loadBasic() //获取基本天气信息 { var location=document.getElementById("input-location").value; axios.get('https://free-api.heweather.net/s6/weather/now?location='+location+'&key=89d49e32a26d4067822c9ed361231e2d') .then(function (response) { document.getElementById("loc").innerHTML=response.data.HeWeather6[0].basic.location; document.getElementById("tmp").innerHTML=response.data.HeWeather6[0].now.tmp; document.getElementById("hum").innerHTML=response.data.HeWeather6[0].now.hum+"%"; document.getElementById("vis").innerHTML=response.data.HeWeather6[0].now.vis+"km"; }) .catch(function (error) { console.log(error); }); } function loadAir() //获取空气质量信息 { //仿照上面的方法 }

axios 是 Vue.js 推荐使用的实现 AJAX 功能的工具,Vue.js 的名气我就不说了,在前端那就是如神器一般的存在。但是我们这里并没有用到 Vue.js。让 Vue.js 和 axios 结合起来该怎么使用呢,请看下文

Vue.js 和 axios 结合

一开始照着网上的教程和自己的摸索,我是这么写的(错误示范):

var vm=new Vue({ el: '#app', data: { inputlocation:' ', loc:'', tmp:'', hum:'', vis:'', aqi:'', update:'' }, methods: { loadBasic:function(){ axios.get('https://free-api.heweather.net/s6/weather/now',{ params:{ location:this.inputlocation, key:'89d49e32a26d4067822c9ed361231e2d' } }) .then(function (response) { this.loc=(response.data.HeWeather6[0].basic.location); this.tmp=response.data.HeWeather6[0].now.tmp; this.hum=response.data.HeWeather6[0].now.hum+"%"; this.vis=response.data.HeWeather6[0].now.vis+"km"; }) .catch(function (error) { console.log(error); }); }, loadAir:function(){ axios.get('https://free-api.heweather.net/s6/air/now',{ params:{ location:this.inputlocation, key:'89d49e32a26d4067822c9ed361231e2d' } }) .then(function (response) { this.update=response.data.HeWeather6[0].update.loc; this.aqi=response.data.HeWeather6[0].air_now_city.aqi; }) .catch(function (error) { console.log(error); }); } } })

同时 HTML 也有较大的改动,我在此列出:

<div class="container " id="app"> <div class="text-center"> <h1>天气查询</h1> <div class="form-inline row"> <input type="text" class="form-control" placeholder="关键字" id="input-location" v-model="inputlocation"/> <button class="btn btn-primary" @click="loadBasic();loadAir()">搜 索</button> </div> </div> <table class="table" > <thead> <tr> <th>位置</th> <th>温度</th> <th>湿度</th> <th>能见度</th> <th>空气质量指数</th> <th>更新时间</th> </tr> </thead> <tbody> <tr> <td id="loc">{{loc}}</td> <td id="tmp">{{tmp}}</td> <td id="hum">{{hum}}</td> <td id="vis">{{vis}}</td> <td id="aqi">{{aqi}}</td> <td id="update">{{update}}</td> </tr> </tbody> </table> </div>

但是发现不成功,而且确认数据应该是绑定上了,甚至在控制台手动执行 axios 方法(将 this 改成 vm)都能成功。后来经过一番搜索,再加上室友的神助攻,发现原来 axios 方法里面的 this 已经不是指向 vm 对象了,因为已经经过了两层方法。这种情况在非严格模式下 this 会被当做 window,在严格模式下 this 不可用。解决这个问题的方法有两种

  1. 在第一层方法内指定 that=this,在第二层方法内把 this 替换成 that
  2. 使用 ES6 的箭头函数

第一种方法的代码如下:

loadBasic:function(){ let that = this; //如果在response方法里用this,会错误 axios.get('https://free-api.heweather.net/s6/weather/now',{ params:{ location:this.inputlocation, key:'89d49e32a26d4067822c9ed361231e2d' } }) .then(function (response) { that.loc=(response.data.HeWeather6[0].basic.location); that.tmp=response.data.HeWeather6[0].now.tmp; that.hum=response.data.HeWeather6[0].now.hum+"%"; that.vis=response.data.HeWeather6[0].now.vis+"km"; }) .catch(function (error) { console.log(error); }); }, loadAir:function(){ let that = this; //如果在response方法里用this,会错误 axios.get('https://free-api.heweather.net/s6/air/now',{ params:{ location:this.inputlocation, key:'89d49e32a26d4067822c9ed361231e2d' } }) .then(function (response) { that.update=response.data.HeWeather6[0].update.loc; that.aqi=response.data.HeWeather6[0].air_now_city.aqi; }) .catch(function (error) { console.log(error); }); }

第二种方法的代码如下

loadBasic:function(){ axios.get('https://free-api.heweather.net/s6/weather/now',{ params:{ location:this.inputlocation, key:'89d49e32a26d4067822c9ed361231e2d' } }) .then((response)=> { this.loc=(response.data.HeWeather6[0].basic.location); this.tmp=response.data.HeWeather6[0].now.tmp; this.hum=response.data.HeWeather6[0].now.hum+"%"; this.vis=response.data.HeWeather6[0].now.vis+"km"; }) .catch(function (error) { console.log(error); }); }, loadAir:function(){ axios.get('https://free-api.heweather.net/s6/air/now',{ params:{ location:this.inputlocation, key:'89d49e32a26d4067822c9ed361231e2d' } }) .then((response)=> { this.update=response.data.HeWeather6[0].update.loc; this.aqi=response.data.HeWeather6[0].air_now_city.aqi; }) .catch(function(error) { console.log(error); }); }

最后成功用现在还算比较新的技术实现了我的网页,还是挺美滋滋的。

  • Vue.js

    Vue.js(读音 /vju ː/,类似于 view)是一个构建数据驱动的 Web 界面库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

    267 引用 • 666 回帖
  • axios
    7 引用 • 5 回帖
  • AJAX
    26 引用 • 96 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...