PS:轉(zhuǎn)載請注明出處
作者: TigerChain
地址: http://www.lxweimin.com/p/2187be164186
本文出自 TigerChain 簡書 手把手教 Vue 系列
教程簡介
- 1、閱讀對象
本篇教程適合新手閱讀,老手直接略過 - 2、教程難度
初級,本人水平有限,文章內(nèi)容難免會出現(xiàn)問題,如果有問題歡迎指出,謝謝 - 3、Demo 地址:https://github.com/tigerchain/vue-lesson
查看 09 、vue 網(wǎng)絡(luò)請求
正文
一、Vue 中的網(wǎng)絡(luò)請求
前幾節(jié)我們說 vue 的基礎(chǔ)知識的時候,說的都是單機應(yīng)用,在這個搶個紅包都要網(wǎng)絡(luò)的時代,單機根本不成不了事的,而 vue 注重的是寫前端組件,對于前后端分離的項目「基于 api 驅(qū)動開發(fā)」,沒有接口「那豈不是扯淡」,這一節(jié)我們就來看看在 vue 中如何從服務(wù)端拿到數(shù)據(jù)
在 js 中,我們知道 ajax 的興起可以說是 js 的一場革命「可以實現(xiàn)異步請求和局部刷新」,使得 Web 站點不僅可以提供靜態(tài)頁面,使得 Web 開發(fā)變成可交互的「推動了 Web 技術(shù)的發(fā)展」
vue 也是基于 js 開發(fā)的,那么 vue 中的網(wǎng)絡(luò)請求有那些呢?
- 1、豪無疑問 ajax 是完全可以使用的,我們可以自己封裝 ajax
- 2、jquery 必須也要以,當(dāng)然 jquery 封裝了 ajax
- 3、vue resource「官方不再推薦」
- 4、axios「官網(wǎng)推薦」
- 5、自己封裝 Promise
- 6、fetch
- 7、搭配 async await「ES8 的特性」
- 8、等等一些其它的請求
二、各個請求的舉例
針對以上的請求我們分別說一下,我們就按上面的順序一個個的來,以下代碼我們?nèi)渴褂?vue-cli 來創(chuàng)建「用法都是在 vue-cli 中的,如果使用 html 引入方式,那就更簡單了,引入封裝好的 js 即可」
1、ajax 網(wǎng)絡(luò)請求
題外話
說點題外話,我發(fā)現(xiàn)了一個奇怪的現(xiàn)象,我和一些開發(fā)人員聊天,甚至是工作好幾年的開發(fā)人員從來沒有自己封裝過 ajax「起碼要知道底層使用啥實現(xiàn)吧」 ,連 jquery 的 ajax 的源碼也沒有了解過,基本上都是說不要重復(fù)造輪子,有現(xiàn)成的使用即可,不要重復(fù)造輪子沒有問題,可是不要忘記了還有下句呢,我們起碼知道輪子是如何造的,如果使用三方組件或是庫,你會「bai」使用「du」,別人也會「bai」使用「du」,你的優(yōu)勢何在?所以我們還是有必要要了解一下 js 原生封裝 ajax 的,有點跑題了,我們言歸正傳
封裝 ajax
在這里我們使用自己封裝一個 ajax 請求來在 vue 中使用,廢話不多說,我們這使用 XMLHttpRequest「就是一個 http 請求對象的封裝,簡稱 XHR」 來封裝我們的 ajax 請求
關(guān)建步驟
我們使用 vue-cli 來創(chuàng)建項目「這里不說了,以前多次講過」- 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 = []
// 遍歷請求參數(shù)對象,拼接請求參數(shù)
for(let param in options.data){
params.push(param +'='+options.data[param])
}
// 給每個數(shù)組后面添加一個 &
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 后面的導(dǎo)出方式」
- (1)、普通的導(dǎo)出方式
這樣想在那個組件中使用,直接 import 進來即可,下面以在 HelloWorld.vue 組件中使用為例,分為兩步
導(dǎo)入自定義 ajax
使用自定義 ajax
在這里我在本地定義一個 json 模擬服務(wù)端數(shù)據(jù)「本地的 json 要放在 static 目錄中,由于 vue-cli 只把 static 文件夾暴漏出去,可以看 webpack 配置,放在別的地方會報找不到錯誤」
運行一把
可以看到,我們的請求是成功的
- (2)、全局使用「引入一次處處使用」
修改 customAjax.js
在這里我們可以使用 Vue.prototype 原型屬性可以讓每個 Vue 實例中都可以使用它,然后我們在 main.js 中引入它「間接的就達到全局使用的目的」,我們修改 customAjax.js 最后的暴露方式,如下圖所示,把其它的注釋掉即可
修改 HelloWorld.vue 中的 ajax 的使用方式
當(dāng)然我們還要修改 ajax 的使用方式,由于我們把 ajax 給 Vue 的使用了,所以我們調(diào)用的時候使用如下方法
我們在 HelloWorld.vue 中使用 this.ajax(xxx) 來調(diào)用 ajax 方法
ps: 這里注意一下,如果我們在 HelloWorld.vue 中引入 ajax
import ajax from '../js/customAjax'
在 main.js 中不引入,那么就是局部使用,如果我們只在 main.js 中引入,那么就是全局使用了
運行查看結(jié)果
結(jié)果照樣出來,沒有問題,這樣就可以所所有的 vue 的實例中使用 ajax 了
- (3)、使用 Vue.use(ajax) 來全局使用
我們在使用 Mint-ui 的時候,或是一般三方組件的時候,除了要引入組件之外,還要使用 Vue.use(xxx) 來使用一下,我們還記得在 Mint-ui 那一節(jié)我們說過,按需引入 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 來調(diào)用
運行查看結(jié)果
運行結(jié)果和上面一毛一樣,這里就不浪費空間來貼圖了
2、使用 jquery 中的 ajax 請求
上面我們說了自定義 ajax「基于 XHR來封裝的」,下面我們來說說如何在 Vue 中引入 jquery 并且使用 jquery 封裝的 ajax
1、初始化項目 jquerydemo
使用 vue-cli 來初始化一個 jquerydemo 的項目「我們輕車熟路了」
2、安裝 jquery
yarn add jquery
ProvidePlugin
我們安裝完成了還不能直接使用,要做一些配置「webpack」,當(dāng)然這里配置有多種方式,我們采用比較常見的一種方式,配置 webpack[圖片上傳中...(webpack-use-jquery.png-664571-1538906442038-0)]
的 ProvidePlugin,我們來看看 webpack 文檔關(guān)于 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 的環(huán)境配好了
修改 HelloWorld.vue 核心代碼
我們來看一下 HelloWorld.vue 的核心代碼,也就是一個 jquery 的 ajax 的使用而已
沒有什么可說的,這里還是使用模擬一個本地的 json 文件來請求,jquery 的 ajax 請求方式這里就不詳細的說明了,看文檔即可「不是本文說的重點」
運行查看結(jié)果
到此 jquery ajax 就說完了,至于 jquery 的其它用法不是我們本節(jié)所關(guān)心的東西「vue 才不關(guān)心什么操作 DOM 呢」
3、vue resource「官方不再推薦了」請求
vue resource 作為曾今 vue 請求推薦的庫「雖然現(xiàn)在不推薦了,但是還是值得一試的」,vue-resource 可以通過XMLHttpRequest或JSONP發(fā)起請求并處理響應(yīng),基本上 ajax 能做的事情,vue-resource 都能做,直接進入正題吧
1、初始化項目 vue-resource-demo
使用 vue-cli 初始化項目 vue-resource-demo
2、安裝 vue-resource
進入到 vue-resource-demo 目錄中執(zhí)行
yarn add vue-resource
3、使用 vue-resource
我們在 main.js 中引入 vue-resource 并且使用它「全局組件都可以使用了」
這樣我們就把 vue-resource 引入到 vue-cli 中了
4、使用 vue-resource 發(fā)起請求
我們來修改 HelloWorld.vue,來看看使用的核心代碼,上面的 demo 中我們只是使用了本地 json 來模擬請求,現(xiàn)在我們再加一個真實的 api 來請求,我們選的是干貨集中營的 api
請求本地 json
請求干貨集中營的福利 api
這里 vue-resource 的具體請求的 api 我們不做過多的說明,這個我們看文檔直接抄過來使用就可以,更多用法我們看文檔即可 https://github.com/pagekit/vue-resource,vue-resource 請求返回的結(jié)果是一個 Promise
運行查看結(jié)果
怎么樣,這樣我們完成了 vue-resource 的一個請求,vue-resource 可以攜帶參數(shù),支持 GET、POST 還支持 jsonp ,具體可以看文檔「這里說沒有什么意義,具體使用看文檔即可」,不過 vue 作者不再推薦使用此庫了「當(dāng)然你可以繼續(xù)使用,這沒有什么問題」
4、使用 axios 請求
axios 簡單的說就是基于 Promise 的一個同時支持瀏覽器和 node.js 的 http 請求客戶端「基于 xhr 封裝,使用 ES 規(guī)范的 Promise 來實現(xiàn)」,它不是 vue 的專利「不像 vue-resource」,理論上它可使用在任何前端請求中
比起 vue-resource 來說它更加靈活,并且同時支持瀏覽器和 node.js,根據(jù)作者的原話說的化認為 vue 不應(yīng)該和 http 請求耦合在一起,應(yīng)該是單獨分離的,所以不再推薦 vue-resourse,我們可以自由選擇要使用的 http 請求庫,單一職責(zé),這很酷,來看看部分截圖
1、初始化項目 axios-demo
使用 vue-cli 初始化 axios-demo 項目
2、安裝 axios
yarn add axios
3、引入 axios
根據(jù)我們傳統(tǒng)的經(jīng)驗 ,我們在 main.js 中 import axios 再 Vue.use(axios) 一把我們就可以使用了,但是我可以很負責(zé)任的告訴你 Vue.use(axios) 不行「它沒有重寫 install 方法,不信看看源碼」,其實這也很容易 理解 axios 又不是 vue 的專屬 ajax 請求庫,React 中也可以使用,別的前端框架中也可以使用,不可能對每個都單獨寫一個配合其的使用方法吧。好吧,那我們使用 Vue.prototype 原型屬性來暴漏 axios 吧
修改 main.js
這樣我們所有的 vue 實例都可以使用 this.$axios 來請求了
4、添加測試代碼
我們還是修改 HelloWorld.vue 來測試 axios「基本上 HelloWorld.vue和上面的一毛一樣」,我們只關(guān)心方法請求部分「其它可以看源碼-會推到 github 上」
axios 請求本地 json
axios 請求遠程 json
看起來和使用 vue-resource 沒有太大區(qū)別,只不過返回結(jié)果封裝不太一樣,前者是把結(jié)果封裝在 response.body 中,后者是封裝在 response.data 中「每個庫機制不一樣,也非常容易理解」,這樣我就完成了 axios 的請求,具體的 api 可以看 https://github.com/axios/axios 非常詳細「這里就不一一列舉了」
運行一把,查看結(jié)果
怎么樣熟悉的界面又一次出來了,還是非常不錯的「注意說的不是美女,是 axios」
axios 我們就大概說到這里,還是那句話,你知道有這么個玩意,具體的就去看文檔「把文檔一個個 api 拿到這里來說,浪費時間和空間」
5、自己封裝 Promise
回調(diào)地域「callback hell」
開發(fā)者都經(jīng)營過回調(diào)地域「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){}
)
}
以上代碼全部是偽代碼「沒有這種方法」就是在一個成功的回調(diào)里面調(diào)用另一個方法,再在另個成功的方法里面調(diào)用另另一個方法「回調(diào)地域由此產(chǎn)生,一個方法依賴于另一個運行結(jié)果」ajax 典型的存在這種情況,這種代碼的可讀性和維護性可不就是地域嗎?Promise 的出現(xiàn)改善了這一過程
當(dāng)然對于 Promise 有各種版本的封裝,各大類庫也都封裝自己的 Promise ,但是在 ES6 中 Promise 被統(tǒng)一規(guī)范了
Promise 通過鏈?zhǔn)秸{(diào)用「玩過 rx 的朋友最熟悉,或者知道建造者設(shè)計模式的也都太熟悉了」,簡單封裝一個 Promise 來常常鮮
定義一個 test 方法「符合 Promise 的執(zhí)行函數(shù)」
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 操作達到鏈?zhǔn)秸{(diào)用并且如果想處理一下結(jié)果給下一個再 then 即可「以上代碼純粹手寫的,不乏有誤,但是道理是清楚的」
Promise 是通過構(gòu)造方法來生成實例的,它依賴兩個東西 resolve 和 reject 我們估且認為這分別是成功的回調(diào)和失敗的回調(diào) promise 就可以任性的 .then 操作了,關(guān)于 Promise 簡介就到這里,更多可以查看
廖雪峰的官網(wǎng)或是阮一峰的關(guān)于 Promise 的介紹「都是不錯的入門文章」,下面我們在 vue-cli 中使用自定義 Promise 來完成請求
2、創(chuàng)建 vue-custom-promise-basedxhr 項目
使用 vue-cli 來創(chuàng)建我們的項目,這里基于 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 實現(xiàn) ajax 的調(diào)用
4、運行一把
怎么樣,完美的實現(xiàn)了自定義 ajax 并且解決了回調(diào)地域的問題,這就是 Proimse 的優(yōu)勢,其實 fetch 就是幫我們干了個事情,我們定義一個 Promise 的請求是為了演示這一過程「當(dāng)然 Promise 不僅僅用在請求上,只要是想鏈?zhǔn)秸{(diào)用都可以使用」
6、使用 fetch 來請求
fetch 是什么東東,fetch 是瀏覽器提供的原生的 ajax 接口。別急等等,不是 XHR 是瀏覽器提供的原生的 ajax 接口嗎?怎么又出來個 fetch「當(dāng)然 fetch 就是替代 XHR 的,但是其底層還是 基于 XHR 來封裝的」
fetch 本質(zhì)就是實現(xiàn) ajax「非 jquery 的 ajax 而是指 XHR」 的封裝以及 Promise 的實現(xiàn),廢話不多說,直接來個 demo
1、創(chuàng)建 vue-fetch-demo
使用 vue-cli 創(chuàng)建一個 vue-fetch-demo
2、使用 fetch
由于是瀏覽器支持的接口「版本支持情況請看」
我們可以在 https://caniuse.com/# 網(wǎng)站中查看,React Jquery 等都可以在此網(wǎng)站中查看瀏覽器版本的支持情況「其中紅色是不支持,綠色是支持」
從上圖我們可以看到 fetch 對 IE 瀏覽器支持的不是很友好,但是如果我們?nèi)绻情_發(fā)手機 WebApp 那么問題不大,好了我們開始使用 fetch 吧,fetch 返回的是一個 Promise
直接在 HelloWorld.vue 中添加 fetch api
使用 fetch 請求遠程服務(wù) api
運行查看結(jié)果
怎么樣還是熟悉的妹子,哦不對熟悉的結(jié)果,具體用法可以查看 https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API 說的很詳細
哎呀不錯哦,又完結(jié)了一個請求,別走開我們繼續(xù)
7、搭配 async await 來完成請求
fetch「Promise的作用」 解決了 ajax 的回調(diào)地域問題,但是過多的 .then 讓人看來很是不爽,ES2017「ES8」中新增了一個 async await 的一個規(guī)范,讓異步實現(xiàn)起來 so easy「使用同步的書寫方法來寫異步,這里不具體展開詳述了」 ,我們可以使用 fetch 配合 async await 來實現(xiàn)一個請求
1、創(chuàng)建 async-await-demo 項目
使用 vue-cli 創(chuàng)建 async-await-demo 項目
2、直接修改 HelloWorld.vue
我們修改 HelloWorld.vue 如下所示,先封裝一個 async 的 fetch 請求方法
定義一個 async 的方法
async 返回的是一個 Promise
async-await 搭配 fetch 請求本地數(shù)據(jù)
async-await 搭配 fetch 請求遠程數(shù)據(jù)
到此我們就把 fetch 拿 async await 封裝了,怎么樣,調(diào)用異步方法如同調(diào)用同步方法一樣爽,也沒有 .then...then 鏈?zhǔn)椒椒耍杏X整個世界都清凈了
3、運行一把看效果
還是熟悉的結(jié)果,哦不對「妹子變了,不要關(guān)心妹子了」
async-await 使異步是如此的簡單,快動手試試吧
三、總結(jié)
這節(jié)我們說了一下 vue 中的 http 請求方法和類庫,并且配合代碼都演示了一下,讓大家有一個知「一定要行,才能達到知行合一」,并沒有具體的對每個請求做具體的說明「由于篇幅有限,大家了解了這些個請求有了一個大體的認識可以自行再深入的了解」,總結(jié)一下吧
- vue 就是一個 View 層,理論上可以和任意的 ajax 請求庫搭配使用
- 本文介紹了 7 種 請求庫在 Vue 中的使用「當(dāng)然不止這 7 種,其它的都類似」
- 如何選擇呢?其它用那種都沒有問題,但是可以根據(jù)項目需求選擇「建議還是使用優(yōu)大大推薦的 axios」
- 查看瀏覽器兼容性可以使用 can i use 網(wǎng)站
- 建議不要使用 jquery「操作 dom 在 Vue 中多少有一點惡心」 了,如果想用 ajax 直接上 axios
- 如果想實現(xiàn)異步那么 async-await 輕松搞定
四、參考資料
點贊富一生,轉(zhuǎn)發(fā)富五代,更多文章請關(guān)注我的微信公號來查閱
公眾號:TigerChain