從零開始學 Web 之 Vue.js(四)Vue的Ajax請求和跨域
大家好,這裡是「 從零開始學 Web 系列教程 」,並在下列地址同步更新......
- github:https://github.com/Daotin/Web
- 微信公眾號: ofollow,noindex" target="_blank">Web前端之巔
- 部落格園:http://www.cnblogs.com/lvonve/
- CSDN:https://blog.csdn.net/lvonve/
在這裡我會從 Web 前端零基礎開始,一步步學習 Web 相關的知識點,期間也會分享一些好玩的專案。現在就讓我們一起進入 Web 前端學習的冒險之旅吧!
一、Vue傳送Ajax請求
之前我們傳送Ajax請求的方式,一是原生的方式傳送,二是通過jQuery來發送Ajax請求。
但是我們知道,在Vue裡面是不推薦使用jQuery的,那麼如何使用Vue來發送Ajax請求呢?
在Vue中可以 使用第三方外掛 vue-resource
來實現Ajax請求的傳送 。
1、vue-resource 安裝
1、通過npm的方式線上安裝: npm install vue-resource
2、在 github 中下載 vue-resource 的 檔案 (在 dist 資料夾下有個 vue-resource.js 檔案。)
3、使用 CDN。 <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
2、vue-resource 使用
參考連結:https://github.com/pagekit/vue-resource/blob/develop/docs/http.md
步驟:
1、在Vue.js之後 引入vue-resource.js檔案 (因為vue-resource.js檔案是依賴於Vue的)
2、全域性使用:
then後面第一個引數是請求成功的回撥函式;第二個引數是請求失敗的回撥函式。
獲取到的結果在回撥函式的引數中。
Vue.http.get('/someUrl', [config]).then(successCallback, errorCallback); Vue.http.post('/someUrl', [body], [config]).then(successCallback, errorCallback); Vue.http.jsonp('/someUrl', [config]).then(successCallback, errorCallback);
3、區域性使用: 在methods的事件中 ,使用 this.$http.get/post/jsonp();
的形式發起請求。
this.$http.get('/someUrl', [config]).then(successCallback, errorCallback); this.$http.post('/someUrl', [body], [config]).then(successCallback, errorCallback); this.$http.jsonp('/someUrl', [config]).then(successCallback, errorCallback);
示例:通過三個按鈕點選分別獲取get,post,jsonp請求。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="./lib/vue-2.4.0.js"></script> <script src="./lib/vue-resource-1.3.4.js"></script> </head> <body> <div id="box"> <input type="button" value="get請求" @click="getClick"> <input type="button" value="post請求" @click="postClick"> <input type="button" value="jsonp請求" @click="jsonpClick"> </div> <script> var vm = new Vue({ el: " #box ", data: {}, methods: { getClick() { // 引數1:測試用的地址:http://vue.studyit.io/api/getlunbo // 引數2:[config] 可選 this.$http.get("http://vue.studyit.io/api/getlunbo").then(result => { console.log("ok"); console.log(result.body); }); }, postClick() { // 引數1:測試用的地址:http://vue.studyit.io/api/getlunbo // 引數2:[data]資料,可為Object,FormData,String,這裡為空 // 引數3:[config] 可選,但是emulateJSON = "true" 表名錶單格式為:application/x-www-form-urlencoded,否則 // 可能有的瀏覽器不認識。 this.$http.post("http://vue.studyit.io/api/post", "", { emulateJSON: true }).then(result => { console.log(result.body); }); }, jsonpClick() { this.$http.jsonp("http://vue.studyit.io/api/getlunbo").then(result => { console.log(result.body); }); } } }); </script> </body> </html>
注意:獲取到的資料在成功回撥函式引數data的中,data是個物件,具體需要的資料是 data.body。
二、vue-resource 跨域請求資料
1、jsonp的實現原理
jsonp主要是為了 解決跨域請求問題 的。
我們知道,由於瀏覽器的安全性限制,不允許AJAX訪問 協議不同 、 域名不同 、 埠號不同 的資料介面,瀏覽器認為這種訪問不安全。
但是, script標籤src屬性中的連結卻可以訪問跨域的js指令碼 ,於是利用這種特性, 我們讓伺服器不再返回資料,而是返回一段呼叫某個函式的js程式碼,然後在script中進行呼叫 ,就實現了跨域。
示例:使用JSONP,添加了一個script標籤,標籤的src指向了另一個域 www.xxx.com下的 jsonp.js 指令碼。
<!DOCTYPE html> <html> <head> <title>title</title> </head> <body> <script type="text/javascript"> function jsonphandle(data){ alert("age:" + data.age + "name:" + data.name); } </script> <script type="text/javascript" src="jquery-1.8.3.min.js"> </script> <script type="text/javascript" src="http://www.xxx.com/jsopn.js"></script> </body> </html>
要實現跨域,所以返回的 js 程式碼應該是一個函式的呼叫。www.xxx.com 下的 jsonp.js 程式碼如下:
jsonphandle({ "age" : 15, "name": "John", })
於是,結果就彈出對話方塊。
我們再改進一下,在script的src中傳入的大多是後臺檔案,這裡以php檔案為例。
由於我們之前傳入 js 檔案只是想得到一個函式的呼叫而已,那麼傳入php檔案怎麼獲取函式的呼叫呢?
<!DOCTYPE html> <html> <head> <title>GoJSONP</title> </head> <body> <script type="text/javascript"> function jsonphandle(data){ alert("age:" + data.age + "name:" + data.name); } </script> <script type="text/javascript" src="jquery-1.8.3.min.js"> </script> <script type="text/javascript"> $(document).ready(function(){ var url = "http://www.xxx.com/jsonp.php?id=1&callback=jsonphandle"; var obj = $('<script><\/script>'); obj.attr("src",url); $("body").append(obj); }); </script> </body> </html>
這裡動態的添加了一個script標籤,src指向跨域的一個php指令碼,並且將上面的js函式名作為callback引數傳入,那麼我們看下PHP程式碼怎麼寫的:
<?php $data = array( 'age' => 20, 'name' => '張三', ); $callback = $_GET['callback']; echo $callback."(".json_encode($data).")"; return;
php程式碼返回的也是一個函式呼叫, 我們需要的資料,就在其引數裡面 。成功彈出提示框:
jsonphandle({ "age" : 15, "name": "張三", })
最後,jQuery提供了方便使用jsonp的方式:
<!DOCTYPE html> <html> <head> <title>GoJSONP</title> </head> <body> <script type="text/javascript" src="jquery-1.8.3.min.js"> </script> <script type="text/javascript"> $(document).ready(function(){ $.ajax({ type : "get", async: false, url : "http://www.xxx.com/jsonp.php?id=1", dataType: "jsonp", jsonp:"callback", //請求php的引數名 jsonpCallback: "jsonhandle",//要執行的回撥函式 success : function(data) { alert("age:" + data.age + "name:" + data.name); } }); }); </script> </body> </html>
其中引數 data,即為php程式碼返回的函式呼叫的引數,就是我們先要的資料。
參考連結:https://blog.csdn.net/u011897301/article/details/52679486
2、跨域獲取電影資訊
這裡我使用 聚合資料 :https://www.juhe.cn 的免費API。
使用方式很簡單,註冊之後,申請資料後,在個人中心->我的資料,介面名稱上方檢視key值。
而我們訪問的url即為: http://v.juhe.cn/movie/index?key=您申請的key&title=頭文字D
我們在name輸入框中輸入電影名稱後,點選查詢按鈕即可顯示相關資訊。
<!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>Document</title> <script src="./lib/vue-2.4.0.js"></script> <script src="./lib/vue-resource-1.3.4.js"></script> <style> * { padding: 0; margin: 0; position: relative; } /* 實現任意無寬高盒子居中 */ #app { width: 100%; position: absolute; left: 50%; /* top: 100px; */ transform: translateX(-50%); } .box { width: 100%; height: 40px; background-color: #ccc; display: inline-block; text-align: center; line-height: 40px; border: 1px solid #aaa; box-sizing: border-box; border-bottom: none; } .box>input[type="button"] { width: 60px; background-color: #aaa; border: 0; border: 1px solid #aaa; margin: 0 20px; } .tb { width: 100%; height: 100%; text-align: center; border-collapse: collapse; border-color: #ccc; } .th { background-color: rgb(24, 204, 204); } </style> </head> <body> <div id="app"> <div class="box"> <label for="name"> 電影名: <input type="text" id="name" v-model="name"> </label> <input type="button" value="查詢" @click="addClick"> </div> <table border="1" cellspacing="0" class="tb"> <thead class="th"> <tr> <th>年份</th> <th>標題</th> <th>評分</th> <th>型別</th> <th>時長</th> <th>主演</th> <th>簡介</th> <th>刪除</th> </tr> </thead> <!-- 有查詢的話,這裡就不應該固定死,而是根據keywords動態生成新的陣列 --> <!-- <tr v-for="item in list"></tr> --> <tbody> <tr v-for="item in list"> <td>{{item.year}}</td> <td>《{{item.title}}》</td> <td>{{item.rating}}</td> <td>{{item.genres}}</td> <td>{{item.runtime}}</td> <td>{{item.actors}}</td> <td>{{item.plot_simple}}</td> <td> <!-- 繫結的事件是可以傳引數的,這裡傳入需要刪除的物件id --> <a href="javascript:;" @click.prevent="delClick(item.id)">del</a> </td> </tr> </tbody> </table> </div> <script> // 全域性配置資料介面的根域名 //Vue.http.options.root = 'http://v.juhe.cn/'; var vm = new Vue({ el: "#app", data: { name: "", rating: "", genres: "", runtime: "", title: "", actors: "", plot_simple: "", year: "", // 假資料 list: [{ 'rating': 7.3, 'genres': '動作/驚悚/科幻', 'runtime': '139分鐘', "title": "哥斯拉", "actors": "馬修·布羅德里克", "plot_simple": "一道亮光劃過天際,太平洋上波濤洶湧", "year": "1998", }, { 'rating': 1, 'genres': 2, 'runtime': 3, "title": 4, "actors": 5, "plot_simple": 6, "year": 7, } ] }, methods: { // 按鈕點選事件處理函式 addClick() { this.getAllList(this.name); this.name = ""; }, // 獲取電影資訊 getAllList(title) { // console.log(2); title = this.name; this.$http.get(`http://v.juhe.cn/movie/index?key=a6c9eddf926517774fe9aa1106ce9295&title=${title}`).then( result => { if (result.body.result.length == 0) { alert("無此電影資訊"); return; } this.list = result.body.result; }); } } }); </script> </body> </html>
由於API要求我們訪問的方式為 get請求,所以我們使用 this.$http.get
的方式來獲取電影資訊。
然後列印獲取到的資料result,但是卻爆出如下錯誤資訊:
錯誤資訊是表示,無法實現跨域。而我們之前知道 jsonp是可以實現跨域問題的。
於是我將get請求改為jsonp請求: this.$http.jsonp
就可以了。
改進:
之前直接把資料介面放在了請求地址裡面,如果地址變了,就要在請求地址裡面修改,如果不止一個還有其他post,get請求等,那麼就要修改多次,所以我們有必要動態的指定資料介面。
使用: Vue.http.options.root = 'http://v.juhe.cn/';
來指定資料介面的根地址。
我們在請求的時候只需要寫 movie/index?key=a6c9eddf926517774fe9aa1106ce9295&title=${title}
就可以了。
注意:後續地址,不要寫 / ,否則就不會將根地址和後續地址進行拼接。
當然,對於我們發給伺服器的資料,可能會需要 emulateJSON = true;
我們也可以進行全域性配置: Vue.http.options.emulateJSON = true;