09 、手把手教Vue--網(wǎng)絡(luò)請求

本節(jié)大綱

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)出方式
普通導(dǎo)出方式

這樣想在那個組件中使用,直接 import 進來即可,下面以在 HelloWorld.vue 組件中使用為例,分為兩步

導(dǎo)入自定義 ajax

普通導(dǎo)入自定義 ajax

使用自定義 ajax

使用自定義 ajax

在這里我在本地定義一個 json 模擬服務(wù)端數(shù)據(jù)「本地的 json 要放在 static 目錄中,由于 vue-cli 只把 static 文件夾暴漏出去,可以看 webpack 配置,放在別的地方會報找不到錯誤」

運行一把

查看結(jié)果

可以看到,我們的請求是成功的

  • (2)、全局使用「引入一次處處使用」

修改 customAjax.js

在這里我們可以使用 Vue.prototype 原型屬性可以讓每個 Vue 實例中都可以使用它,然后我們在 main.js 中引入它「間接的就達到全局使用的目的」,我們修改 customAjax.js 最后的暴露方式,如下圖所示,把其它的注釋掉即可

vue-prototype-ajax

修改 HelloWorld.vue 中的 ajax 的使用方式

當(dāng)然我們還要修改 ajax 的使用方式,由于我們把 ajax 給 Vue 的使用了,所以我們調(diào)用的時候使用如下方法

vue-prototype-ajax-use

我們在 HelloWorld.vue 中使用 this.ajax(xxx) 來調(diào)用 ajax 方法

ps: 這里注意一下,如果我們在 HelloWorld.vue 中引入 ajax

import ajax from '../js/customAjax' 在 main.js 中不引入,那么就是局部使用,如果我們只在 main.js 中引入,那么就是全局使用了

運行查看結(jié)果

查看結(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,如下所示:

vue-install-ajax

修改 main.js

ajax-install-main-js-include

這樣我們就要以使用 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-provideplugin

webpack 中配置 jquery

我們來配置一下 webpack.base.conf.js,配置之前,再來看一下 webpack 文檔中如何配置 jquery

webpack-use-jquery

修改 webpack.base.conf.js

沒有什么好說的,我們依"浮"蘆畫瓢來配置一下我們的 webpack.base.conf.js 如下所示:

首先我們引入 webapck

var webpack = require("webpack")

再者我們在 module.exports 下添加

配置 webpack.base.config.js 中的 jquery

這樣我們就在 vue-cli 中把 jquery 的環(huán)境配好了

修改 HelloWorld.vue 核心代碼

我們來看一下 HelloWorld.vue 的核心代碼,也就是一個 jquery 的 ajax 的使用而已

jquery-ajax-use

沒有什么可說的,這里還是使用模擬一個本地的 json 文件來請求,jquery 的 ajax 請求方式這里就不詳細的說明了,看文檔即可「不是本文說的重點」

運行查看結(jié)果

vue-cli 中 jquery ajax 使用

到此 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 并且使用它「全局組件都可以使用了」

main.js 中使用 vue-resource

這樣我們就把 vue-resource 引入到 vue-cli 中了

4、使用 vue-resource 發(fā)起請求

我們來修改 HelloWorld.vue,來看看使用的核心代碼,上面的 demo 中我們只是使用了本地 json 來模擬請求,現(xiàn)在我們再加一個真實的 api 來請求,我們選的是干貨集中營的 api

請求本地 json

vue-resource 請求本地 json

請求干貨集中營的福利 api

vue-resource 請求 gnkio 數(shù)據(jù)

這里 vue-resource 的具體請求的 api 我們不做過多的說明,這個我們看文檔直接抄過來使用就可以,更多用法我們看文檔即可 https://github.com/pagekit/vue-resource,vue-resource 請求返回的結(jié)果是一個 Promise

運行查看結(jié)果

vue-resource 請求結(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é),這很酷,來看看部分截圖

去掉 vue-resource
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

在 main.js 中引入 axios

這樣我們所有的 vue 實例都可以使用 this.$axios 來請求了

4、添加測試代碼

我們還是修改 HelloWorld.vue 來測試 axios「基本上 HelloWorld.vue和上面的一毛一樣」,我們只關(guān)心方法請求部分「其它可以看源碼-會推到 github 上」

axios 請求本地 json

axios 請求本地 json

axios 請求遠程 json

axios 請求遠程 json

看起來和使用 vue-resource 沒有太大區(qū)別,只不過返回結(jié)果封裝不太一樣,前者是把結(jié)果封裝在 response.body 中,后者是封裝在 response.data 中「每個庫機制不一樣,也非常容易理解」,這樣我就完成了 axios 的請求,具體的 api 可以看 https://github.com/axios/axios 非常詳細「這里就不一一列舉了」

運行一把,查看結(jié)果

顯示 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 本地請求方法

遠程請求方法

自定義 promise 遠程請求方法

以下就完成了自定義 promise 實現(xiàn) ajax 的調(diào)用

4、運行一把

自定義 promise 實現(xiàn) ajax 結(jié)果

怎么樣,完美的實現(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

由于是瀏覽器支持的接口「版本支持情況請看」

fetch 支持的瀏覽器版本

我們可以在 https://caniuse.com/# 網(wǎng)站中查看,React Jquery 等都可以在此網(wǎng)站中查看瀏覽器版本的支持情況「其中紅色是不支持,綠色是支持」

從上圖我們可以看到 fetch 對 IE 瀏覽器支持的不是很友好,但是如果我們?nèi)绻情_發(fā)手機 WebApp 那么問題不大,好了我們開始使用 fetch 吧,fetch 返回的是一個 Promise

直接在 HelloWorld.vue 中添加 fetch api

fetch 請求本地 json

使用 fetch 請求遠程服務(wù) api

fetch 請求遠程 json

運行查看結(jié)果

fetch 請求結(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 的方法

async 返回的是一個 Promise

async-await 搭配 fetch 請求本地數(shù)據(jù)

async-await 搭配 fetch 請求本地數(shù)據(jù)

async-await 搭配 fetch 請求遠程數(shù)據(jù)

async-await 搭配 fetch 請求遠程數(shù)據(jù)

到此我們就把 fetch 拿 async await 封裝了,怎么樣,調(diào)用異步方法如同調(diào)用同步方法一樣爽,也沒有 .then...then 鏈?zhǔn)椒椒耍杏X整個世界都清凈了

3、運行一把看效果
async-await-fetch 結(jié)果

還是熟悉的結(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。