PS:转载请注明出处
作者: TigerChain
地址: https://www.jianshu.com/p/2187be164186
本文出自 TigerChain 手把手教 Vue 系列
教程简介
- 1、阅读对象
本篇教程适合新手阅读,老手直接略过 - 2、教程难度
初级,本人水平有限,文章内容难免会出现问题,如果有问题欢迎指出,谢谢 - 3、Demo 地址:https://github.com/tigerchain/vue-lesson
查看 09 、vue 网络请求
正文
一、Vue 中的网络请求
前几节我们说 vue 的基础知识的时候,说的都是单机应用,在这个抢个红包都要网络的时代,单机根本不成不了事的,而 vue 注重的是写前端组件,对于前后端分离的项目「基于 api 驱动开发」,没有接口「那岂不是扯淡」,这一节我们就来看看在 vue 中如何从服务端拿到数据
在 js 中,我们知道 ajax 的兴起可以说是 js 的一场革命「可以实现异步请求和局部刷新」,使得 Web 站点不仅可以提供静态页面,使得 Web 开发变成可交互的「推动了 Web 技术的发展」
vue 也是基于 js 开发的,那么 vue 中的网络请求有那些呢?
- 1、豪无疑问 ajax 是完全可以使用的,我们可以自己封装 ajax
- 2、jquery 必须也要以,当然 jquery 封装了 ajax
- 3、vue resource「官方不再推荐」
- 4、axios「官网推荐」
- 5、自己封装 Promise
- 6、fetch
- 7、搭配 async await「ES8 的特性」
- 8、等等一些其它的请求
二、各个请求的举例
针对以上的请求我们分别说一下,我们就按上面的顺序一个个的来,以下代码我们全部使用 vue-cli 来创建「用法都是在 vue-cli 中的,如果使用 html 引入方式,那就更简单了,引入封装好的 js 即可」
1、ajax 网络请求
题外话
说点题外话,我发现了一个奇怪的现象,我和一些开发人员聊天,甚至是工作好几年的开发人员从来没有自己封装过 ajax「起码要知道底层使用啥实现吧」 ,连 jquery 的 ajax 的源码也没有了解过,基本上都是说不要重复造轮子,有现成的使用即可,不要重复造轮子没有问题,可是不要忘记了还有下句呢,我们起码知道轮子是如何造的,如果使用三方组件或是库,你会「bai」使用「du」,别人也会「bai」使用「du」,你的优势何在?所以我们还是有必要要了解一下 js 原生封装 ajax 的,有点跑题了,我们言归正传
封装 ajax
在这里我们使用自己封装一个 ajax 请求来在 vue 中使用,废话不多说,我们这使用 XMLHttpRequest「就是一个 http 请求对象的封装,简称 XHR」 来封装我们的 ajax 请求
关建步骤
我们使用 vue-cli 来创建项目「这里不说了,以前多次讲过」- customAjaxDemo
1、封装 ajax 代码
# customAjax.js
import Vue from 'vue'
function ajax(options) {
options = options || {}
// 默认是 GET 请求
options.methods = options.methods.toUpperCase() || 'GET'
options.url = options.url || ''
// 默认是异步请求
options.async = options.async || true
options.data = options.data || {}
options.success = options.success || function() {}
options.faile = options.faile || function () {}
console.log(options)
let xhr = null
if(window.XMLHttpRequest) {
xhr = new XMLHttpRequest()
}else {
xhr = new ActiveXObject("Microsoft.XMLHTTP")
}
let params = []
// 遍历请求参数对象,拼接请求参数
for(let param in options.data){
params.push(param +'='+options.data[param])
}
// 给每个数组后面添加一个 &
let requestData = params.join('&')
// 请求类型
let requestType = options.methods.toUpperCase()
// 如果是 GET 请求
if(requestType == 'GET'){
xhr.open(requestType,options.url+'?'+requestData,options.async)
xhr.send()
}else if(requestType == 'POST'){ // 如果是 POST 请求
xhr.open(requestType,options.url,options.async)
xhr.setRequestHeader("Content-type",
"application/x-www-form-urlencoded;charset=utf-8");
xhr.send(requestData)
}
xhr.onreadystatechange = function() {
if (xhr.readyState==4 && xhr.status==200) {
options.success(JSON.parse(xhr.responseText))
}else if(xhr.status!=200) {
options.faile('request error')
}
}
}
// 在 vue 中全局注册 这样可以直接使用不使用 Vue.use() 方式
// Vue.prototype.ajax = ajax
export default {
install(Vue,options){
// 在 vue 中全局注册
Vue.prototype.ajax = ajax
}
}
由于我们要 vue 中使用,所以我们要使用 vue 把这个 js 暴露出去,可以是供全局使用,也可以在单个组件中引用使用「按需使用」
2、使用 customAjax.js
这里有三种方式使用,通过修改 customAjax.js 中 export 的方式和 vue 全局使用的方式可以有三种方式「修改 customAjax.js 后面的导出方式」
- (1)、普通的导出方式
这样想在那个组件中使用,直接 import 进来即可,下面以在 HelloWorld.vue 组件中使用为例,分为两步
导入自定义 ajax
使用自定义 ajax
在这里我在本地定义一个 json 模拟服务端数据「本地的 json 要放在 static 目录中,由于 vue-cli 只把 static 文件夹暴漏出去,可以看 webpack 配置,放在别的地方会报找不到错误」
运行一把
可以看到,我们的请求是成功的
- (2)、全局使用「引入一次处处使用」
修改 customAjax.js
在这里我们可以使用 Vue.prototype 原型属性可以让每个 Vue 实例中都可以使用它,然后我们在 main.js 中引入它「间接的就达到全局使用的目的」,我们修改 customAjax.js 最后的暴露方式,如下图所示,把其它的注释掉即可
修改 HelloWorld.vue 中的 ajax 的使用方式
当然我们还要修改 ajax 的使用方式,由于我们把 ajax 给 Vue 的使用了,所以我们调用的时候使用如下方法
我们在 HelloWorld.vue 中使用 this.ajax(xxx) 来调用 ajax 方法
ps: 这里注意一下,如果我们在 HelloWorld.vue 中引入 ajax
import ajax from '../js/customAjax'
在 main.js 中不引入,那么就是局部使用,如果我们只在 main.js 中引入,那么就是全局使用了
运行查看结果
结果照样出来,没有问题,这样就可以所所有的 vue 的实例中使用 ajax 了
- (3)、使用 Vue.use(ajax) 来全局使用
我们在使用 Mint-ui 的时候,或是一般三方组件的时候,除了要引入组件之外,还要使用 Vue.use(xxx) 来使用一下,我们还记得在 Mint-ui 那一节我们说过,按需引入 Mint-ui 组件的时候,官方说的 Vue.use(xxx) 组件方法我们验证是使用不了「目前来说,以后版本可能会支持」,只能使用 Vue.component(Component.name, Component) 这种方法来全局注册组件「原因也说过了,就是没有添加能使用 use 的方法」
修改 customAjax.js
对于一个自定义的组件,如果想供全局使用并且可以使用 Vue.use 方法,那么我们就要重写 install 方法,废话不多说,我们直接看代码,还是修改 customAjax.js,如下所示:
修改 main.js
这样我们就要以使用 Vue.use(ajax) 来全局使用 ajax 了,也要使用 this.ajax 来调用
运行查看结果
运行结果和上面一毛一样,这里就不浪费空间来贴图了
2、使用 jquery 中的 ajax 请求
上面我们说了自定义 ajax「基于 XHR来封装的」,下面我们来说说如何在 Vue 中引入 jquery 并且使用 jquery 封装的 ajax
1、初始化项目 jquerydemo
使用 vue-cli 来初始化一个 jquerydemo 的项目「我们轻车熟路了」
2、安装 jquery
yarn add jquery
ProvidePlugin
我们安装完成了还不能直接使用,要做一些配置「webpack」,当然这里配置有多种方式,我们采用比较常见的一种方式,配置 webpack[图片上传中...(webpack-use-jquery.png-664571-1538906442038-0)]
的 ProvidePlugin,我们来看看 webpack 文档关于 ProvidePlugin 说明:http://www.css88.com/doc/webpack/plugins/provide-plugin/,部分截图如下
webpack 中配置 jquery
我们来配置一下 webpack.base.conf.js,配置之前,再来看一下 webpack 文档中如何配置 jquery
修改 webpack.base.conf.js
没有什么好说的,我们依"浮"芦画瓢来配置一下我们的 webpack.base.conf.js 如下所示:
首先我们引入 webapck
var webpack = require("webpack")
再者我们在 module.exports 下添加
这样我们就在 vue-cli 中把 jquery 的环境配好了
修改 HelloWorld.vue 核心代码
我们来看一下 HelloWorld.vue 的核心代码,也就是一个 jquery 的 ajax 的使用而已
没有什么可说的,这里还是使用模拟一个本地的 json 文件来请求,jquery 的 ajax 请求方式这里就不详细的说明了,看文档即可「不是本文说的重点」
运行查看结果
到此 jquery ajax 就说完了,至于 jquery 的其它用法不是我们本节所关心的东西「vue 才不关心什么操作 DOM 呢」
3、vue resource「官方不再推荐了」请求
vue resource 作为曾今 vue 请求推荐的库「虽然现在不推荐了,但是还是值得一试的」,vue-resource 可以通过XMLHttpRequest或JSONP发起请求并处理响应,基本上 ajax 能做的事情,vue-resource 都能做,直接进入正题吧
1、初始化项目 vue-resource-demo
使用 vue-cli 初始化项目 vue-resource-demo
2、安装 vue-resource
进入到 vue-resource-demo 目录中执行
yarn add vue-resource
3、使用 vue-resource
我们在 main.js 中引入 vue-resource 并且使用它「全局组件都可以使用了」
这样我们就把 vue-resource 引入到 vue-cli 中了
4、使用 vue-resource 发起请求
我们来修改 HelloWorld.vue,来看看使用的核心代码,上面的 demo 中我们只是使用了本地 json 来模拟请求,现在我们再加一个真实的 api 来请求,我们选的是干货集中营的 api
请求本地 json
请求干货集中营的福利 api
这里 vue-resource 的具体请求的 api 我们不做过多的说明,这个我们看文档直接抄过来使用就可以,更多用法我们看文档即可 https://github.com/pagekit/vue-resource,vue-resource 请求返回的结果是一个 Promise
运行查看结果
怎么样,这样我们完成了 vue-resource 的一个请求,vue-resource 可以携带参数,支持 GET、POST 还支持 jsonp ,具体可以看文档「这里说没有什么意义,具体使用看文档即可」,不过 vue 作者不再推荐使用此库了「当然你可以继续使用,这没有什么问题」
4、使用 axios 请求
axios 简单的说就是基于 Promise 的一个同时支持浏览器和 node.js 的 http 请求客户端「基于 xhr 封装,使用 ES 规范的 Promise 来实现」,它不是 vue 的专利「不像 vue-resource」,理论上它可使用在任何前端请求中
比起 vue-resource 来说它更加灵活,并且同时支持浏览器和 node.js,根据作者的原话说的化认为 vue 不应该和 http 请求耦合在一起,应该是单独分离的,所以不再推荐 vue-resourse,我们可以自由选择要使用的 http 请求库,单一职责,这很酷,来看看部分截图
1、初始化项目 axios-demo
使用 vue-cli 初始化 axios-demo 项目
2、安装 axios
yarn add axios
3、引入 axios
根据我们传统的经验 ,我们在 main.js 中 import axios 再 Vue.use(axios) 一把我们就可以使用了,但是我可以很负责任的告诉你 Vue.use(axios) 不行「它没有重写 install 方法,不信看看源码」,其实这也很容易 理解 axios 又不是 vue 的专属 ajax 请求库,React 中也可以使用,别的前端框架中也可以使用,不可能对每个都单独写一个配合其的使用方法吧。好吧,那我们使用 Vue.prototype 原型属性来暴漏 axios 吧
修改 main.js
这样我们所有的 vue 实例都可以使用 this.$axios 来请求了
4、添加测试代码
我们还是修改 HelloWorld.vue 来测试 axios「基本上 HelloWorld.vue和上面的一毛一样」,我们只关心方法请求部分「其它可以看源码-会推到 github 上」
axios 请求本地 json
axios 请求远程 json
看起来和使用 vue-resource 没有太大区别,只不过返回结果封装不太一样,前者是把结果封装在 response.body 中,后者是封装在 response.data 中「每个库机制不一样,也非常容易理解」,这样我就完成了 axios 的请求,具体的 api 可以看 https://github.com/axios/axios 非常详细「这里就不一一列举了」
运行一把,查看结果
怎么样熟悉的界面又一次出来了,还是非常不错的「注意说的不是美女,是 axios」
axios 我们就大概说到这里,还是那句话,你知道有这么个玩意,具体的就去看文档「把文档一个个 api 拿到这里来说,浪费时间和空间」
5、自己封装 Promise
回调地域「callback hell」
开发者都经营过回调地域「callback hell」,下面的伪代码说明一下
// 分别定义三个方法
function getData1(){}
function getData2(){}
function getData3(){}
function request(data,callback){
request.http(data,function success(res){
if(res.status=='0001'){
getData1(res.data,function success(response){
if(response.status=='0001'){
getData2(response.data,function success(data){
getData3(.....)
},
function error(error){})
}
},
function error(err){}
)
}
},
function error(err){}
)
}
以上代码全部是伪代码「没有这种方法」就是在一个成功的回调里面调用另一个方法,再在另个成功的方法里面调用另另一个方法「回调地域由此产生,一个方法依赖于另一个运行结果」ajax 典型的存在这种情况,这种代码的可读性和维护性可不就是地域吗?Promise 的出现改善了这一过程
当然对于 Promise 有各种版本的封装,各大类库也都封装自己的 Promise ,但是在 ES6 中 Promise 被统一规范了
Promise 通过链式调用「玩过 rx 的朋友最熟悉,或者知道建造者设计模式的也都太熟悉了」,简单封装一个 Promise 来常常鲜
定义一个 test 方法「符合 Promise 的执行函数」
function test(resolve, reject){
let i = 0 ;
setTimeout(function(){
if(i == 0){
resolve('cuccess')
}else {
reject('error')
}
},1000)
}
使用 Promise 来封装
const promise = new Promise(test)
promise.then(function(result){
var myResult = result+' ok'
return myResult
}).then(function(myResult){
console.log(myResult)
}).catch(function(error){
console.log(error)
})
怎么样,通过 then 操作达到链式调用并且如果想处理一下结果给下一个再 then 即可「以上代码纯粹手写的,不乏有误,但是道理是清楚的」
Promise 是通过构造方法来生成实例的,它依赖两个东西 resolve 和 reject 我们估且认为这分别是成功的回调和失败的回调 promise 就可以任性的 .then 操作了,关于 Promise 简介就到这里,更多可以查看
廖雪峰的官网或是阮一峰的关于 Promise 的介绍「都是不错的入门文章」,下面我们在 vue-cli 中使用自定义 Promise 来完成请求
2、创建 vue-custom-promise-basedxhr 项目
使用 vue-cli 来创建我们的项目,这里基于 XHR 来封装请求
1、自定义 requst.js「在 scr/js 目录下」
const fetchServer = function(url,obj){
obj = obj || {}
obj.methods = obj.methods.toUpperCase() || 'GET'
obj.async = obj.async || true
obj.data = obj.data || {}
const promise = new Promise(function(resolve,reject){
var xhr = null
if(window.XMLHttpRequest) {
xhr = new XMLHttpRequest()
}else {
xhr = new ActiveXObject("Microsoft.XMLHTTP")
}
var params = []
..... 省略若干代码,和前面的自定义 ajax 代码一样
xhr.onreadystatechange = function() {
if(xhr.readyState == 4){
if(xhr.status == 200) {
resolve(JSON.parse(xhr.responseText), this)
}else {
reject({code:250,message:"请求失败"}, this)
}
}
}
})
return promise
}
export default fetchServer
这样我们就完成了一个使用 Promise 来自定义的一个 ajax 请求
2、在 main.js 的中引入,并供 vue 实例使用
import fetchServer from './js/request.js'
Vue.prototype.fetchServer = fetchServer
3、修改 HelloWorld.vue
本地请求方法
远程请求方法
以下就完成了自定义 promise 实现 ajax 的调用
4、运行一把
怎么样,完美的实现了自定义 ajax 并且解决了回调地域的问题,这就是 Proimse 的优势,其实 fetch 就是帮我们干了个事情,我们定义一个 Promise 的请求是为了演示这一过程「当然 Promise 不仅仅用在请求上,只要是想链式调用都可以使用」
6、使用 fetch 来请求
fetch 是什么东东,fetch 是浏览器提供的原生的 ajax 接口。别急等等,不是 XHR 是浏览器提供的原生的 ajax 接口吗?怎么又出来个 fetch「当然 fetch 就是替代 XHR 的,但是其底层还是 基于 XHR 来封装的」
fetch 本质就是实现 ajax「非 jquery 的 ajax 而是指 XHR」 的封装以及 Promise 的实现,废话不多说,直接来个 demo
1、创建 vue-fetch-demo
使用 vue-cli 创建一个 vue-fetch-demo
2、使用 fetch
由于是浏览器支持的接口「版本支持情况请看」
我们可以在 https://caniuse.com/# 网站中查看,React Jquery 等都可以在此网站中查看浏览器版本的支持情况「其中红色是不支持,绿色是支持」
从上图我们可以看到 fetch 对 IE 浏览器支持的不是很友好,但是如果我们如果是开发手机 WebApp 那么问题不大,好了我们开始使用 fetch 吧,fetch 返回的是一个 Promise
直接在 HelloWorld.vue 中添加 fetch api
使用 fetch 请求远程服务 api
运行查看结果
怎么样还是熟悉的妹子,哦不对熟悉的结果,具体用法可以查看 https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API 说的很详细
哎呀不错哦,又完结了一个请求,别走开我们继续
7、搭配 async await 来完成请求
fetch「Promise的作用」 解决了 ajax 的回调地域问题,但是过多的 .then 让人看来很是不爽,ES2017「ES8」中新增了一个 async await 的一个规范,让异步实现起来 so easy「使用同步的书写方法来写异步,这里不具体展开详述了」 ,我们可以使用 fetch 配合 async await 来实现一个请求
1、创建 async-await-demo 项目
使用 vue-cli 创建 async-await-demo 项目
2、直接修改 HelloWorld.vue
我们修改 HelloWorld.vue 如下所示,先封装一个 async 的 fetch 请求方法
定义一个 async 的方法
async 返回的是一个 Promise
async-await 搭配 fetch 请求本地数据
async-await 搭配 fetch 请求远程数据
到此我们就把 fetch 拿 async await 封装了,怎么样,调用异步方法如同调用同步方法一样爽,也没有 .then...then 链式方法了,感觉整个世界都清净了
3、运行一把看效果
还是熟悉的结果,哦不对「妹子变了,不要关心妹子了」
async-await 使异步是如此的简单,快动手试试吧
三、总结
这节我们说了一下 vue 中的 http 请求方法和类库,并且配合代码都演示了一下,让大家有一个知「一定要行,才能达到知行合一」,并没有具体的对每个请求做具体的说明「由于篇幅有限,大家了解了这些个请求有了一个大体的认识可以自行再深入的了解」,总结一下吧
- vue 就是一个 View 层,理论上可以和任意的 ajax 请求库搭配使用
- 本文介绍了 7 种 请求库在 Vue 中的使用「当然不止这 7 种,其它的都类似」
- 如何选择呢?其它用那种都没有问题,但是可以根据项目需求选择「建议还是使用优大大推荐的 axios」
- 查看浏览器兼容性可以使用 can i use 网站
- 建议不要使用 jquery「操作 dom 在 Vue 中多少有一点恶心」 了,如果想用 ajax 直接上 axios
- 如果想实现异步那么 async-await 轻松搞定
四、参考资料
- 理解 JavaScript 的 async/await
- Jquery ajax, Axios, Fetch区别之我见
点赞富一生,转发富五代,更多文章请关注我的微信公号来查阅
公众号:TigerChain