1. 程式人生 > >Vue.js——vue-resource全攻略

Vue.js——vue-resource全攻略

lam 類型 網絡 java 隱藏 header 做的 response scrip

概述

上一篇我們介紹了如何將$.ajax和Vue.js結合在一起使用,並實現了一個簡單的跨域CURD示例。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上加個星星!

GitHub Source

本文的所有示例如下:

  • http get示例
  • http jsonp示例
  • http post示例
  • http put示例
  • http delete示例
  • resource get示例
  • resource save示例(HTTP POST)
  • resource update示例(HTTP PUT)
  • resource remove示例(HTTP DELETE)
  • inteceptor示例1——ajax請求的loading界面
  • inteceptor實例2——請求失敗時的提示對話框

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

vue-resource特點

vue-resource插件具有以下特點:

1. 體積小

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

2. 支持主流的瀏覽器

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

3. 支持Promise API和URI Templates

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 Object, FormData string request body
params Object 請求的URL參數對象
headers Object request header
timeout number 單位為毫秒的請求超時時間 (0 表示無超時時間)
before function(request) 請求發送前的處理函數,類似於jQuery的beforeSend函數
progress function(event) ProgressEvent回調處理函數
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。

技術分享圖片

View Demo

JSONP請求

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

View Demo

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

技術分享圖片

View Demo

PUT請求

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

技術分享圖片

View Demo

Delete請求

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

技術分享圖片

View Demo

使用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)
        })
}

View Demo

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
}

View Demo

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

View Demo

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()
        })
}

View Demo

使用inteceptor

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

技術分享圖片

基本用法

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 sk-bounce3"></div>
        </div>
    </div>
</template>

2.將loading組件作為另外一個Vue實例的子組件

var help = new Vue({
    el: ‘#help‘,
    data: {
        showLoading: false
    },
    components: {
        ‘loading‘: {
            template: ‘#loading-template‘,
        }
    }
})

3.將該Vue實例掛載到某個HTML元素

<div id="help">
    <loading v-show="showLoading"></loading>
</div>

4.添加inteceptor

Vue.http.interceptors.push((request, next) => {
    loading.show = true
    next((response) => {
        loading.show = false
        return response
    });
});

技術分享圖片

View Demo

示例2

當用戶在畫面上停留時間太久時,畫面數據可能已經不是最新的了,這時如果用戶刪除或修改某一條數據,如果這條數據已經被其他用戶刪除了,服務器會反饋一個404的錯誤,但由於我們的put和delete請求沒有處理errorCallback,所以用戶是不知道他的操作是成功還是失敗了。

你問我為什麽不在每個請求裏面處理errorCallback,這是因為我比較懶。這個問題,同樣也可以通過inteceptor解決。

1. 繼續沿用上面的loading組件,在#help元素下加一個對話框

<div id="help">
    <loading v-show="showLoading" ></loading>
    <modal-dialog :show="showDialog">
        <header class="dialog-header" slot="header">
            <h1 class="dialog-title">Server Error</h1>
        </header>
        <div class="dialog-body" slot="body">
            <p class="error">Oops,server has got some errors, error code: {{errorCode}}.</p>
        </div>
    </modal-dialog>
</div>

2.給help實例的data選項添加兩個屬性

var help = new Vue({
        el: ‘#help‘,
        data: {
            showLoading: false,
            showDialog: false,
            errorCode: ‘‘
        },
        components: {
            ‘loading‘: {
                template: ‘#loading-template‘,
            }
        }
    })

3.修改inteceptor

Vue.http.interceptors.push((request, next) => {
    help.showLoading = true
    next((response) => {
        if(!response.ok){
            help.errorCode = response.status
            help.showDialog = true
        }
        help.showLoading = false
        return response
    });
});

技術分享圖片

View Demo

總結

vue-resource是一個非常輕量的用於處理HTTP請求的插件,它提供了兩種方式來處理HTTP請求:

  • 使用Vue.http或this.$http
  • 使用Vue.resource或this.$resource

這兩種方式本質上沒有什麽區別,閱讀vue-resource的源碼,你可以發現第2種方式是基於第1種方式實現的。

inteceptor可以在請求前和請求後附加一些行為,這意味著除了請求處理的過程,請求的其他環節都可以由我們來控制。

參考鏈接:https://github.com/vuejs/vue-resource/tree/master/docs

Vue.js——vue-resource全攻略