1. 程式人生 > >Vue1.0介面請求之vue-resource全攻略

Vue1.0介面請求之vue-resource全攻略

Vue.js是資料驅動的,這使得我們並不需要直接操作DOM,如果我們不需要使用jQuery的DOM選擇器,就沒有必要引入jQuery。vue-resource是Vue.js的一款外掛,它可以通過XMLHttpRequest或JSONP發起請求並處理響應。也就是說,$.ajax能做的事情,vue-resource外掛一樣也能做到,而且vue-resource的API更為簡潔。另外,vue-resource還提供了非常有用的inteceptor功能,使用inteceptor可以在請求前和請求後附加一些行為,比如使用inteceptor在ajax請求時顯示loading介面。

本文的主要內容如下:

  • 介紹vue-resource的特點
  • 介紹vue-resource的基本使用方法
  • 基於this.$http的增刪查改示例
  • 基於this.$resource的增刪查改示例
  • 基於inteceptor實現請求等待時的loading畫面
  • 基於inteceptor實現請求錯誤時的提示畫面

本文11個示例的原始碼已放到GitHub,如果您覺得本篇內容不錯,請點個贊,或在GitHub上加個星星!

本文的所有示例如下:

各位在閱讀這篇文章的內容時,可以先嚐試該列表的最後兩個示例,這兩個示例綜合使用了this.$http和inteceptor。

vue-resource特點

vue-resource外掛具有以下特點:

1. 體積小

vue-resource非常小巧,在壓縮以後只有大約12KB,服務端啟用gzip壓縮後只有4.5KB大小,這遠比jQuery的體積要小得多。

2. 支援主流的瀏覽器

和Vue.js一樣,vue-resource除了不支援IE 9以下的瀏覽器,其他主流的瀏覽器都支援。

Promise是ES6的特性,Promise的中文含義為“先知”,Promise物件用於非同步計算。
URI Templates表示URI模板,有些類似於ASP.NET MVC的路由模板。

4. 支援攔截器

攔截器是全域性的,攔截器可以在請求傳送前和傳送請求後做一些處理。
攔截器在一些場景下會非常有用,比如請求傳送前在headers中設定access_token,或者在請求失敗時,提供共通的處理方式。

vue-resource使用

引入vue-resource

<script src="js/vue.js"></script>
<script src="js/vue-resource.js"></script>

基本語法

引入vue-resource後,可以基於全域性的Vue物件使用http,也可以基於某個Vue例項使用http。

// 基於全域性Vue物件使用http
Vue.http.get('/someUrl', [options]).then(successCallback, errorCallback);
Vue.http.post('/someUrl', [body], [options]).then(successCallback, errorCallback);

// 在一個Vue例項內使用$http
this.$http.get('/someUrl', [options]).then(successCallback, errorCallback);
this.$http.post('/someUrl', [body], [options]).then(successCallback, errorCallback);

在傳送請求後,使用then方法來處理響應結果,then方法有兩個引數,第一個引數是響應成功時的回撥函式,第二個引數是響應失敗時的回撥函式。

then方法的回撥函式也有兩種寫法,第一種是傳統的函式寫法,第二種是更為簡潔的ES 6的Lambda寫法:

// 傳統寫法
this.$http.get('/someUrl', [options]).then(function(response){
    // 響應成功回撥
}, function(response){
    // 響應錯誤回撥
});


// Lambda寫法
this.$http.get('/someUrl', [options]).then((response) => {
    // 響應成功回撥
}, (response) => {
    // 響應錯誤回撥
});

PS:做過.NET開發的人想必對Lambda寫法有一種熟悉的感覺。

支援的HTTP方法

vue-resource的請求API是按照REST風格設計的,它提供了7種請求API:

  • get(url, [options])
  • head(url, [options])
  • delete(url, [options])
  • jsonp(url, [options])
  • post(url, [body], [options])
  • put(url, [body], [options])
  • patch(url, [body], [options])

除了jsonp以外,另外6種的API名稱是標準的HTTP方法。當服務端使用REST API時,客戶端的編碼風格和服務端的編碼風格近乎一致,這可以減少前端和後端開發人員的溝通成本。

客戶端請求方法 服務端處理方法
this.$http.get(...) Getxxx
this.$http.post(...) Postxxx
this.$http.put(...) Putxxx
this.$http.delete(...) Deletexxx

options物件

傳送請求時的options選項物件包含以下屬性:

引數 型別 描述
url string 請求的URL
method string 請求的HTTP方法,例如:'GET', 'POST'或其他HTTP方法
body ObjectFormData string request body
params Object 請求的URL引數物件
headers Object request header
timeout number 單位為毫秒的請求超時時間 (0 表示無超時時間)
before function(request) 請求傳送前的處理函式,類似於jQuery的beforeSend函式
progress function(event)
credentials boolean 表示跨域請求時是否需要使用憑證
emulateHTTP boolean 傳送PUT, PATCH, DELETE請求時以HTTP POST的方式傳送,並設定請求頭的X-HTTP-Method-Override
emulateJSON boolean 將request body以application/x-www-form-urlencoded content type傳送

emulateHTTP的作用

如果Web伺服器無法處理PUT, PATCH和DELETE這種REST風格的請求,你可以啟用enulateHTTP現象。啟用該選項後,請求會以普通的POST方法發出,並且HTTP頭資訊的X-HTTP-Method-Override屬性會設定為實際的HTTP方法。

Vue.http.options.emulateHTTP = true;

emulateJSON的作用

如果Web伺服器無法處理編碼為application/json的請求,你可以啟用emulateJSON選項。啟用該選項後,請求會以application/x-www-form-urlencoded作為MIME type,就像普通的HTML表單一樣。

Vue.http.options.emulateJSON = true;

response物件

response物件包含以下屬性:

方法 型別 描述
text() string 以string形式返回response body
json() Object 以JSON物件形式返回response body
blob() Blob 以二進位制形式返回response body
屬性 型別 描述
ok boolean 響應的HTTP狀態碼在200~299之間時,該屬性為true
status number 響應的HTTP狀態碼
statusText string 響應的狀態文字
headers Object 響應頭

注意:本文的vue-resource版本為v0.9.3,如果你使用的是v0.9.0以前的版本,response物件是沒有json(), blob(), text()這些方法的。

CURD示例

提示:以下示例仍然沿用上一篇的元件和WebAPI,元件的程式碼和頁面HTML程式碼我就不再貼出來了。

GET請求

var demo = new Vue({
    el: '#app',
    data: {
        gridColumns: ['customerId', 'companyName', 'contactName', 'phone'],
        gridData: [],
        apiUrl: 'http://211.149.193.19:8080/api/customers'
    },
    ready: function() {
        this.getCustomers()
    },
    methods: {
        getCustomers: function() {
            this.$http.get(this.apiUrl)
                .then((response) => {
                    this.$set('gridData', response.data)
                })
                .catch(function(response) {
                    console.log(response)
                })
        }
    }
})

這段程式的then方法只提供了successCallback,而省略了errorCallback。
catch方法用於捕捉程式的異常,catch方法和errorCallback是不同的,errorCallback只在響應失敗時呼叫,而catch則是在整個請求到響應過程中,只要程式出錯了就會被呼叫。

在then方法的回撥函式內,你也可以直接使用this,this仍然是指向Vue例項的:

getCustomers: function() {
    this.$http.get(this.apiUrl)
        .then((response) => {
            this.$set('gridData', response.data)
        })
        .catch(function(response) {
            console.log(response)
        })
}

為了減少作用域鏈的搜尋,建議使用一個區域性變數來接收this。

image

JSONP請求

getCustomers: function() {
    this.$http.jsonp(this.apiUrl).then(function(response){
        this.$set('gridData', response.data)
    })
}

POST請求

var demo = new Vue({
    el: '#app',
    data: {
        show: false,
        gridColumns: [{
            name: 'customerId',
            isKey: true
        }, {
            name: 'companyName'
        }, {
            name: 'contactName'
        }, {
            name: 'phone'
        }],
        gridData: [],
        apiUrl: 'http://211.149.193.19:8080/api/customers',
        item: {}
    },
    ready: function() {
        this.getCustomers()
    },
    methods: {
        closeDialog: function() {
            this.show = false
        },
        getCustomers: function() {
            var vm = this
            vm.$http.get(vm.apiUrl)
                .then((response) => {
                    vm.$set('gridData', response.data)
                })
        },
        createCustomer: function() {
            var vm = this
            vm.$http.post(vm.apiUrl, vm.item)
                .then((response) => {
                    vm.$set('item', {})
                    vm.getCustomers()
                })
            this.show = false
        }
    }
})

29

PUT請求

updateCustomer: function() {
    var vm = this
    vm.$http.put(this.apiUrl + '/' + vm.item.customerId, vm.item)
        .then((response) => {
            vm.getCustomers()
        })
}

30

Delete請求

deleteCustomer: function(customer){
    var vm = this
    vm.$http.delete(this.apiUrl + '/' + customer.customerId)
        .then((response) => {
            vm.getCustomers()
        })
}

31

使用resource服務

vue-resource提供了另外一種方式訪問HTTP——resource服務,resource服務包含以下幾種預設的action:

get: {method: 'GET'},
save: {method: 'POST'},
query: {method: 'GET'},
update: {method: 'PUT'},
remove: {method: 'DELETE'},
delete: {method: 'DELETE'}

resource物件也有兩種訪問方式:

  • 全域性訪問:Vue.resource
  • 例項訪問:this.$resource

resource可以結合URI Template一起使用,以下示例的apiUrl都設定為{/id}了:

apiUrl: 'http://211.149.193.19:8080/api/customers{/id}'

GET請求

使用get方法傳送GET請求,下面這個請求沒有指定{/id}

getCustomers: function() {

    var resource = this.$resource(this.apiUrl)
        vm = this

    resource.get()
        .then((response) => {
            vm.$set('gridData', response.data)
        })
        .catch(function(response) {
            console.log(response)
        })
}

POST請求

使用save方法傳送POST請求,下面這個請求沒有指定{/id}

createCustomer: function() {
    var resource = this.$resource(this.apiUrl)
        vm = this
        
    resource.save(vm.apiUrl, vm.item)
        .then((response) => {
            vm.$set('item', {})
            vm.getCustomers()
        })
    this.show = false
}

PUT請求

使用update方法傳送PUT請求,下面這個請求指定了{/id}

updateCustomer: function() {
    var resource = this.$resource(this.apiUrl)
        vm = this
        
    resource.update({ id: vm.item.customerId}, vm.item)
        .then((response) => {
            vm.getCustomers()
        })
}

{/id}相當於一個佔位符,當傳入實際的引數時該佔位符會被替換。
例如,{ id: vm.item.customerId}中的vm.item.customerId為12,那麼傳送的請求URL為:

http://211.149.193.19:8080/api/customers/12

DELETE請求

使用remove或delete方法傳送DELETE請求,下面這個請求指定了{/id}

deleteCustomer: function(customer){
    var resource = this.$resource(this.apiUrl)
        vm = this
        
    resource.remove({ id: customer.customerId})
        .then((response) => {
            vm.getCustomers()
        })
}

使用inteceptor

攔截器可以在請求傳送前和傳送請求後做一些處理。

image

基本用法

Vue.http.interceptors.push((request, next) => {
        // ...
        // 請求傳送前的處理邏輯
        // ...
    next((response) => {
        // ...
        // 請求傳送後的處理邏輯
        // ...
        // 根據請求的狀態,response引數會返回給successCallback或errorCallback
        return response
    })
})

在response返回給successCallback或errorCallback之前,你可以修改response中的內容,或做一些處理。
例如,響應的狀態碼如果是404,你可以顯示友好的404介面。

如果不想使用Lambda函式寫法,可以用平民寫法:

Vue.http.interceptors.push(function(request, next) {
    // ...
    // 請求傳送前的處理邏輯
    // ...
    next(function(response) {
        // ...
        // 請求傳送後的處理邏輯
        // ...
        // 根據請求的狀態,response引數會返回給successCallback或errorCallback
        return response
    })
})

示例1

之前的CURD示例有一處使用者體驗不太好,使用者在使用一些功能的時候如果網路較慢,畫面又沒有給出反饋,使用者是不知道他的操作是成功還是失敗的,他也不知道是否該繼續等待。

通過inteceptor,我們可以為所有的請求處理加一個loading:請求傳送前顯示loading,接收響應後隱藏loading。

具體步驟如下:

1.新增一個loading元件

<template id="loading-template">
    <div class="loading-overlay">
        <div class="sk-three-bounce">
            <div class="sk-child sk-bounce1"></div>
            <div class="sk-child sk-bounce2"></div>
            <div class="sk-child