從零開始學 Web 之 Vue.js(四)Vue的Ajax請求和跨域

你們好,這裏是「 從零開始學 Web 系列教程 」,並在下列地址同步更新......javascript

  • github:https://github.com/Daotin/Web
  • 微信公衆號:Web前端之巔
  • 博客園:http://www.cnblogs.com/lvonve/
  • CSDN:https://blog.csdn.net/lvonve/

在這裏我會從 Web 前端零基礎開始,一步步學習 Web 相關的知識點,期間也會分享一些好玩的項目。如今就讓咱們一塊兒進入 Web 前端學習的冒險之旅吧!php

1、Vue發送Ajax請求

以前咱們發送Ajax請求的方式,一是原生的方式發送,二是經過jQuery來發送Ajax請求。html

可是咱們知道,在Vue裏面是不推薦使用jQuery的,那麼如何使用Vue來發送Ajax請求呢?前端

在Vue中能夠使用第三方插件vue-resource 來實現Ajax請求的發送vue

一、vue-resource 安裝

一、經過npm的方式在線安裝:npm install vue-resourcejava

二、在 github 中下載 vue-resource 的 文件 (在 dist 文件夾下有個 vue-resource.js 文件。)jquery

三、使用 CDN。<script src="https://cdn.jsdelivr.net/npm/vue-resource@1.5.1"></script>git

二、vue-resource 使用

參考連接:https://github.com/pagekit/vue-resource/blob/develop/docs/http.mdgithub

步驟:ajax

一、在Vue.js以後引入vue-resource.js文件(由於vue-resource.js文件是依賴於Vue的)

二、全局使用:

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);

三、局部使用:在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。

2、vue-resource 跨域請求數據

一、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

二、跨域獲取電影信息

這裏我使用 聚合數據: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;

相關文章
相關標籤/搜索