一、案例
本次要做的案例的是使用jsonp製作一個查詢天氣情況的網頁,我會從如何抓取數據接口,到一步一步完成這個案例來詳細講解。
這個頁面樣式非常簡單,截圖如下。用户需要先選擇一個城市,然後點擊查看天氣,那麼最近5天的天氣數據,就會展示到下面。
二、數據從何而來
當然我們不可能自己建氣象站,我們只有通過互聯網拿到別人“分享”給我們的數據接口,然後通過這個數據接口獲取全國的氣象數據。這樣我們就必須使用jsonp了,因為提供氣象數據服務的api,其所在的域名肯定跟我們自己的應用程序不是一個域名。
那麼問題來了,我們如何知道哪裏有api提供氣象數據服務的?這個就要多觀察多積累了。比如現在很多人的電腦上都會安裝360,一般360殺毒在安裝時候會篡改你的瀏覽器主頁為“hao360”這個網站,那麼你打開網頁,每次都會看到這樣的畫面。
這個網站在非常顯眼的地方提供了一個查看天氣的模塊。難道360還開着氣象站?如果不是,那我們只要看看它是如何搞到數據的,我們就能如法炮製了。
一般你可以這樣做:
1.在氣象模塊上點鼠標右鍵->審查元素。去看看他的結構
2.打開開發者選項工具窗口,點擊Network(網絡)選項卡,然後去查看請求報文,這樣就能找到氣象數據從哪兒來了。
不過,如果你沒有經驗,你會被請求報文列表中的數據給嚇住,因為實在是太多了,至少不下300條請求項。那我們怎麼去找真正需要的那個請求呢?
試想,這個hao360也不可能自己弄個氣象站,所以它必然也是抓取的第三方api,所以也必然是通過jsonp的形式來實現的。那麼我們只需要在所有的請求報文中按type這一列排下序,然後就只管看請求類型是script的那些項。這樣一下就把範圍縮小了很多很多。
最後我們找到,這裏的請求url是:https://cdn.weather.hao.360.cn/sed_api_weather_info.php?code=101180201&app=hao360&_jsonp=__jsonp3__
簡單説明下這個url的參數
1.code:要查詢的城市編碼,這個可以百度
2._jsonp:你自己定義的回調函數的名字。
3.其他的參數都無關緊要,至少對本案例來説是這樣。
在瀏覽器裏打開這個鏈接,你看到的結果是這樣的:
當然,我只截取了一小部分。不過已經可以看出了,這是一個典型的jsonp跨域訪問。
然後,我把數據copy出來,貼到sublime中,格式化之後,數據是這個樣子的。
1 {
2 "pubdate": "2018-06-25",
3 "pubtime": "16:44:10",
4 "time": 1529916250,
5 "area": [
6 ["\u6cb3\u5357", "18"],
7 ["\u5b89\u9633", "1802"],
8 ["\u5b89\u9633", "101180201"]
9 ],
10 "weather": [{
11 "date": "2018-06-25",
12 "info": {
13 "dawn": ["2", "\u9634", "24", "\u5357\u98ce", "\u5fae\u98ce", "19:44"],
14 "day": ["8", "\u4e2d\u96e8", "27", "\u5317\u98ce", "\u5fae\u98ce", "05:07"],
15 "night": ["8", "\u4e2d\u96e8", "22", "\u897f\u98ce", "\u5fae\u98ce", "19:44"]
16 }
17 }, {
18 "date": "2018-06-26",
19 "info": {
20 "dawn": ["8", "\u4e2d\u96e8", "22", "\u897f\u98ce", "\u5fae\u98ce", "19:44"],
21 "day": ["7", "\u5c0f\u96e8", "28", "\u5357\u98ce", "\u5fae\u98ce", "05:07"],
22 "night": ["1", "\u591a\u4e91", "22", "\u5357\u98ce", "\u5fae\u98ce", "19:44"]
23 }
24 }, {
25 "date": "2018-06-27",
26 "info": {
27 "dawn": ["1", "\u591a\u4e91", "22", "\u5357\u98ce", "\u5fae\u98ce", "19:44"],
28 "day": ["0", "\u6674", "37", "\u5357\u98ce", "\u5fae\u98ce", "05:08"],
29 "night": ["0", "\u6674", "24", "\u5317\u98ce", "3-5\u7ea7", "19:44"]
30 }
31 }, {
32 "date": "2018-06-28",
33 "info": {
34 "dawn": ["0", "\u6674", "24", "\u5317\u98ce", "3-5\u7ea7", "19:44"],
35 "day": ["0", "\u6674", "36", "\u4e1c\u5317\u98ce", "\u5fae\u98ce", "05:08"],
36 "night": ["1", "\u591a\u4e91", "21", "\u897f\u98ce", "\u5fae\u98ce", "19:45"]
37 }
38 }, {
39 "date": "2018-06-29",
40 "info": {
41 "dawn": ["1", "\u591a\u4e91", "21", "\u897f\u98ce", "\u5fae\u98ce", "19:45"],
42 "day": ["1", "\u591a\u4e91", "35", "\u4e1c\u5357\u98ce", "\u5fae\u98ce", "05:08"],
43 "night": ["1", "\u591a\u4e91", "22", "\u5357\u98ce", "\u5fae\u98ce", "19:45"]
44 }
45 }],
46 。。。。。。
47 }
簡單解釋下數據:
1.這裏只截取了數據的一部分,只保留了我們案例中需要用到的那一小部分,感興趣的自己去研究吧。
2.顯然,這個數據是js中的,json格式數據。
3.本案例中用到的氣象數據,是在這個json對象的“weather”屬性中。這個屬性的值是一個js數組,數組一共有5個元素,每個元素又是一個json對象,每個json對象都代表了一天的天氣情況。
三、案例的HTML結構
先看下頁面的HTML結構
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>天氣預報-hao360接口</title>
<link rel="stylesheet" href="css/weather.css">
</head>
<body>
<div class="wt_container">
<div class="city">
<select id="selCity">
<option value="101180201">大安陽</option>
<option value="101010100">北京</option>
<option value="101180101">鄭州</option>
<option value="101250101">長沙</option>
<option value="101050101">哈爾濱</option>
<option value="101130101">烏魯木齊</option>
<option value="101280101">廣州</option>
</select>
<button id="btn">查看天氣</button>
</div>
<div class="weather">
<ul id="wtInfo">
<!-- <li>
<h2>25日</h2>
<div class="day">
<h3>白天天氣</h3>
<p>天氣:</p>
<p>温度</p>
<p>風向</p>
<p>風速</p>
</div>
<div class="night">
<h3>夜間天氣</h3>
<p>天氣:</p>
<p>温度</p>
<p>風向</p>
<p>風速</p>
</div>
</li> -->
</ul>
</div>
</div>
</body>
</html>
大家都看得懂,簡單説明下:
1.select標籤中的每個選項都有一個value值,這個值對應的城市編碼,這個編碼是國家標準編碼,不是自己隨便亂寫的,我是從百度出來然後寫死到頁面上的。當然,網上也有關於提供省市編碼查詢的api,你完全可以根據本案例所講的方法,結合之前AJAX中講的省市聯動的案例,把這裏城市的選擇做成活的。我這裏為了簡單起見,隨便從網上扒了幾個城市,把城市的code拷貝了一下就寫死到HTML了。目的只是為了讓例子別太複雜。
2.由於我們拿到的數據是5天的數據,所以我們用一個<ul id = "wtInof">標籤來展示所有的查詢到的5天的天氣,每天的天氣用一個li包住。HTML中註釋掉的部分就是模擬數據。
我們在js部分,只需要通過jsonp請求道數據,然後按照模擬數據的格式,填充到ul裏就行了。
四、案例的js部分
直接看代碼
1 <script src="js/jquery-3.3.1.js"></script>
2 <script>
3 function callback(data){
4 //1.清空ul#wtInfo
5 $("#wtInfo").html("");
6 //2.呈現數據
7 var wt = data.weather;
8 $.each(wt, function(index, ele){
9 var date = ele.date;
10 var day = ele.info.day;
11 var night = ele.info.night;
12 var tag = "<li>";
13 tag += "<h2>" + date + "</h2>";
14 tag += "<div class='day'>";
15 tag += "<h3>白天天氣</h3>";
16 tag += "<p>天氣:" + day[1] + "</p>";
17 tag += "<p>温度:" + day[2] + "</p>";
18 tag += "<p>風向:" + day[3] + "</p>";
19 tag += "<p>風速:" + day[4] + "</p>";
20 tag += "</div>";
21 tag += "<div class='night'>";
22 tag += "<h3>夜間天氣</h3>";
23 tag += "<p>天氣:" + night[1] + "</p>";
24 tag += "<p>温度:" + night[2] + "</p>";
25 tag += "<p>風向:" + night[3] + "</p>";
26 tag += "<p>風速:" + night[4] + "</p>";
27 tag += "</div>";
28 tag += "</li>";
29 $("#wtInfo").append(tag);
30 });
31 }
32 $(function () {
33 $("#btn").on("click", function () {
34 var cityCode = $("#selCity option:selected").val();
35 var url =
36 'https://cdn.weather.hao.360.cn/sed_api_weather_info.php?app=hao360&_jsonp=callback&code=' +
37 cityCode;
38 $("body").append($("<script src='" + url + "'><script>"));
39 })
40 })
41 </script>
代碼解釋:
1.這用到了jQuery,所以第1行代碼先引入了jQuery包
2.jsonp的原理是通過<script>標籤發出請求,而本例中不希望一打開網頁就顯示某一個城市的天氣數據,而是要先選擇一個,然後點擊查詢按鈕,才發出請求,得到氣象數據, 展示數據。
3.所以我們的思路是:肯定不能在頁面上寫死那個做jsonp請求的<script src = "......">標籤。我們的做法是,當點擊按鈕時,我們動態的獲取到所選select標籤中城市的code,然後拼寫出待請求的url,最後在文檔(document)的body標籤底部,動態添加這個做jsonp請求的<script src = "......">標籤。
4.代碼中定義的function callback(data)函數,就是用來做回調函數的,在這個回調函數中,主要功能就是解析json數據,然後填充到ul中。本身代碼邏輯不復雜,就是拼寫每個li,以及li裏邊的各項元素有點費事而已。
五、後記
這個案例,到這裏就結束了。我再補充2點:
1.這個案例中需要大量拼寫HTML標籤代碼,這麼做是相當費時費力的,而且容易出錯;一旦開發一個複雜點的頁面,這麼做是非常痛苦的。如何改進?我們可以使用模板技術。前端模板插件很多,最流行的前端模板就是art-template.js,大家可以從網上下載。我在這裏給出使用該模板改造本例後的js代碼,具體這個art-template怎麼用,大家看看他官服的demo就一目瞭然,非常簡單。
<script src="js/template.js"></script>
<script id="weatherTemp" type="text/html">
<li>
<h2><%= date %></h2>
<div class="day">
<h3>白天天氣</h3>
<% for(var i=1; i < info.day.length; i++){%>
<p><%= info.day[i]%></p>
<% }%>
</div>
<div class="night">
<h3>夜間天氣</h3>
<% for(var i=1; i < info.night.length; i++){%>
<p><%= info.night[i]%></p>
<% }%>
</div>
</li>
</script>
<script>
function callback(data) {
//1.清空ul#wtInfo
$("#wtInfo").html("");
//2.呈現數據
var wt = data.weather;
$.each(wt, function (index, ele) {
var html = template("weatherTemp", ele)
$("#wtInfo").append(html);
});
}
$(function () {
$("#btn").on("click", function () {
var cityCode = $("#selCity option:selected").val();
var url =
'https://cdn.weather.hao.360.cn/sed_api_weather_info.php?app=hao360&_jsonp=callback&code=' +
cityCode;
$("body").append($("<script src='" + url + "'><script>"));
})
})
</script>
2.如果我們每次都去分析別人的報文,那將是一個非常痛苦的過程。好在現在有專業的,專門提供數據服務的web api提供商,比如“聚合數據”,百度api商店等等,還有很多,大家可以去網上搜索下。其中有免費的,有付費的。比如聚合數據,申請賬號是免費的,提供的服務有的免費,有的付費,不過即使是付費的,也可以免費使用1000次,對於我們學習來説1000次夠玩了。