前言
之前曾經想自己寫一個天氣的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不可用。解決這個問題的方法有兩種
- 在第一層方法內指定
that=this
,在第二層方法內把this替換成that - 使用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);
});
}
最后成功用現在新潮的技術實現了我的網頁,還是挺美滋滋的。