上一篇咱们介绍了如何将$.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界面。javascript
本文的主要内容以下:html
本文11个示例的源码已放到GitHub,若是您以为本篇内容不错,请点个赞,或在GitHub上加个星星!前端
本文的全部示例以下:java
各位在阅读这篇文章的内容时,能够先尝试该列表的最后两个示例,这两个示例综合使用了this.$http和inteceptor。git
vue-resource插件具备如下特色:github
1. 体积小ajax
vue-resource很是小巧,在压缩之后只有大约12KB,服务端启用gzip压缩后只有4.5KB大小,这远比jQuery的体积要小得多。json
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,或者在请求失败时,提供共通的处理方式。
<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写法有一种熟悉的感受。
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选项对象包含如下属性:
参数 | 类型 | 描述 |
---|---|---|
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发送 |
若是Web服务器没法处理PUT, PATCH和DELETE这种REST风格的请求,你能够启用enulateHTTP现象。启用该选项后,请求会以普通的POST方法发出,而且HTTP头信息的X-HTTP-Method-Override
属性会设置为实际的HTTP方法。
Vue.http.options.emulateHTTP = true;
若是Web服务器没法处理编码为application/json的请求,你能够启用emulateJSON选项。启用该选项后,请求会以application/x-www-form-urlencoded
做为MIME type,就像普通的HTML表单同样。
Vue.http.options.emulateJSON = true;
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()这些方法的。
提示:如下示例仍然沿用上一篇的组件和WebAPI,组件的代码和页面HTML代码我就再也不贴出来了。
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。
getCustomers: function() { this.$http.jsonp(this.apiUrl).then(function(response){ this.$set('gridData', response.data) }) }
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 } } })
updateCustomer: function() { var vm = this vm.$http.put(this.apiUrl + '/' + vm.item.customerId, vm.item) .then((response) => { vm.getCustomers() }) }
deleteCustomer: function(customer){ var vm = this vm.$http.delete(this.apiUrl + '/' + customer.customerId) .then((response) => { vm.getCustomers() }) }
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请求,下面这个请求没有指定{/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) }) }
使用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 }
使用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
使用remove或delete方法发送DELETE请求,下面这个请求指定了{/id}
。
deleteCustomer: function(customer){ var resource = this.$resource(this.apiUrl) vm = this resource.remove({ id: customer.customerId}) .then((response) => { vm.getCustomers() }) }
拦截器能够在请求发送前和发送请求后作一些处理。
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 }) })
以前的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 }); });
当用户在画面上停留时间过久时,画面数据可能已经不是最新的了,这时若是用户删除或修改某一条数据,若是这条数据已经被其余用户删除了,服务器会反馈一个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 }); });
vue-resource是一个很是轻量的用于处理HTTP请求的插件,它提供了两种方式来处理HTTP请求:
这两种方式本质上没有什么区别,阅读vue-resource的源码,你能够发现第2种方式是基于第1种方式实现的。
inteceptor能够在请求前和请求后附加一些行为,这意味着除了请求处理的过程,请求的其余环节均可以由咱们来控制。