AJAX(七)jsonp實戰--天氣預報
一、案例
本次要做的案例的是使用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次夠玩了。
AJAX(七)jsonp實戰--天氣預報