日志

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

 来源    2019-06-05    0  

前言

之前曾经想自己写一个天气的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);
    });
}

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

三种JS截取字符串方法
日志JS提供三个截取字符串的方法,分别是:slice(),substring()和substr(),它们都可以接受一个或两个参数: var stmp = "rcinn.cn"; 使用一 ...
三种迭代Java ArrayList方法及比较
日志闲来无事,研究一下Java Collection,首先是ArrayList. 通过三种方式遍历了长度为100000的ArrayList. import java.util.*; public clas ...
窗体间传递数据(跨控件跨类),三种情况与处理方法
日志环境:Qt5.5 MCVS2013 IDE:QtCreator 范例代码下载地址:http://download.csdn.net/detail/shihoongbo/9134859 发现很多Qt的初 ...
三种样式表插入方法
日志外部样式表: <link rel="stylesheet " type="text/css" href="Mystyle.css"&g ...
python三种导入模块的方法和区别
日志方法一: import modname 模块是指一个可以交互使用,或者从另一Python 程序访问的代码段.只要导入了一个模块,就可以引用它的任何公共的函数.类或属性.模块可以通过这种方法来 使用其它 ...
转 python 三种遍历list的方法
日志[转]python 三种遍历list的方法 #!/usr/bin/env python # -*- coding: utf-8 -*- if __name__ == '__main__': list ...
iOS用三种途径实现一方法有多个返回值
日志以前觉得这种标题有点偏向于理论,实际开发中怎么会有这种诡异的需求,但是真正遇到了这种硬需求时觉得还是有那么点价值的,理论付诸了实践在此也就做了个整理. 以我私下开发中的一处代码为例,本意是希望有这么一 ...
Java 线程的深入研究1 Java 提供了三种创建线程的方法
日志Java 提供了三种创建线程的方法: 通过实现 Runnable 接口: 通过继承 Thread 类本身: 通过 Callable 和 Future 创建线程. 1.通过实现 Runnable 接口来 ...
三种初步简易的方法求解数值问题 of C++
日志1. “二分法解方程” 在二分法中,从区间[a,b]开始,用函数值f(a)与f(b)拥有相反的符号.如果f在这个区间连续,则f的图像至少在x=a,x=b之间穿越x轴一次,因此方程f(x)=0在[a,b ...
读书笔记 iOS-开发技巧-三种收起键盘的方法
日志- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typica ...
Linux操作系统下的三种Java环境配置方法
日志方法1:修改/etc/profile 文件     所有用户的 shell都有权使用这些环境变量  (1)在 shell终端执行命令:vi /etc/profile     (2)在 profile文 ...
三种读写XML的方法
日志XML文件是一种常用的文件格式,例如WinForm里面的app.config以及Web程序中的web.config文件,还有许多重要的场所都有它的身影.Xml是Internet环境中跨平台的,依赖于内 ...
三种实现Ajax的方式
日志本文主要是比较三种实现Ajax的方式 1. prototype.js 2. jquery1.3.2.min.js 3. json2.js Java代码 收藏代码 后台处理程序(Servlet),访问路 ...
PHP.23-ThinkPHP框架的三种模型实例化-(D()方法与M()方法的区别)
日志三种模型实例化 原则上:每个数据表应对应一个模型类(Home/Model/GoodsModel.class.php --> 表tp_goods) 1.直接实例化 和实例化其他类库一样实例化模型类 ...
java三种实现线程的方法比较
日志1.继承Thread 2.实现Runnable 1和2的比较,1可以创建不同的任务,每个任务互不干扰,对于2,相当于只执行一个任务,多个任务之间互相影响,比如售票系统,每售出一张票,票数都要减1,这个 ...
nodejs Express 4.x req.body req.query req.params 三种获取参数的方法
日志第一种情况:http://localhost:3000/testparams/lixing,服务端代码这样写: router.get('/testparams/:anything', function ...
(转载)查看三种MySQL字符集的方法
日志(转载)http://database.51cto.com/art/201010/229171.htm MySQL字符集多种多样,下面为您列举了其中三种最常见的MySQL字符集查看方法,该方法供您参考 ...
JAVA基础知识之多线程——三种实现多线程的方法及区别
日志所有JAVA线程都必须是Thread或其子类的实例. 继承Thread类创建线程 步骤如下, 定义Thead子类并实现run()方法,run()是线程执行体 创建此子类实例对象,即创建了线程对象 调用 ...
(转)maven怎么 引入(或引用/使用) 自定义(或本地/第三方) jar的三种方式 图文教程 方法二最简单
日志转:https://blog.csdn.net/wabiaozia/article/details/52798194 准备工作: 假如我有一个自定义jar是:123456.jar,下载地址http:/ ...