vue路由切換時取消之前的所有請求操作
在main.js文件里
import router from 'router/';
import Vue from 'vue';
Vue.Cancel = [];
router.beforeEach((to, from, next) => {
while (Vue.Cancel.length > 0) {
Vue.Cancel.shift()('cancel');
}
next();
})
ajax文件
import Vue from 'vue';
import axios from 'axios';
import VueAxios from 'vue-axios';
Vue.use(VueAxios, axios);
// 導(dǎo)入封裝的回調(diào)函數(shù)
import {
cbs,
gbs
} from 'config/';
// 動態(tài)設(shè)置本地和線上接口域名
Vue.axios.defaults.baseURL = gbs.host;
/**
* 封裝axios的通用請求
* @param {string} type get或post
* @param {string} url 請求的接口URL
* @param {object} data 傳的參數(shù),沒有則傳空對象
* @param {object} urlParams url傳參
* @param {Function} fn 回調(diào)函數(shù)
* @param {boolean} tokenFlag 是否需要攜帶token參數(shù),為true,不需要;false,需要。一般除了登錄,都需要
*/
export default function ({
type,
path,
data,
params,
urlParams,
fn,
errFn,
tokenFlag,
headers,
opts
} = {}) {
var options = {
method: type,
url: path,
params: params,
headers: headers && typeof headers === 'object' ? headers : {},
cancelToken: new axios.CancelToken(function (cancel) {
Vue.Cancel && Vue.Cancel.push(cancel)
})
};
//檢測接口權(quán)限
var api_flag = true;
if (options.url && options.url.indexOf(gbs.host) && this.$store.state.user.userinfo.access_status === 1) {
var url = options.url.replace(gbs.host, '');
var api_routers = this.$store.state.user.userinfo.api_routers;
if (!api_routers || !api_routers.constructor === Object || !api_routers[url]) {
api_flag = false;
}
}
var urlParamsArray = [];
if (api_flag === true) {
options[type === 'get' ? 'params' : 'data'] = data;
// 用于url傳參
if (typeof (urlParams) == "object") {
for (var k in urlParams) {
urlParamsArray.push(k + '=' + urlParams[k])
}
options.url += '?' + urlParamsArray.join('&');
}
if (typeof (urlParams) == "string" || typeof (urlParams) == "number") {
options.url += urlParams;
}
if(options.url.indexOf('?') > -1){
options.url += '&_=' + (new Date()).getTime();
}else{
options.url += '?_=' + (new Date()).getTime();
}
// 分發(fā)顯示加載樣式任務(wù)
this.$store.dispatch('show_loading');
if (tokenFlag !== true) {
//如果你們的后臺不會接受headers里面的參數(shù),打開這個注釋,即實現(xiàn)token通過普通參數(shù)方式傳
// data.token = this.$store.state.user.userinfo.token;
options.headers.token = this.$store.state.user.userinfo.token;
}
//擴展Promise使支持finally(),用了babel就不用手寫了^.^
// Promise.prototype.finally=function(callback){
// let Promise = this.constructor;
// return this.then(
// value => Promise.resolve(callback()).then(() => value),
// reason => Promise.resolve(callback()).then(() => { throw reason })
// );
// };
//發(fā)送請求
return new Promise((resolve, reject)=>{
Vue.axios(options).then((res) => {
this.$store.dispatch('hide_loading');
if (res.data[gbs.api_status_key_field] === gbs.api_status_value_field || (res.status === gbs.api_status_value_field && !res.data[gbs.api_status_key_field])) {
fn(res.data);
} else {
if (gbs.api_custom[res.data[gbs.api_status_key_field]]) {
gbs.api_custom[res.data[gbs.api_status_key_field]].call(this, res.data);
} else {
cbs.statusError.call(this, res.data);
if (errFn) {
errFn.call(this, res.data);
}
}
}
resolve(res.data);
}).catch((err) => {
if(err.response && err.response.status !== 403){
try{
errFn?errFn.call(this, this.$$lib__.isObject(err.response.data) ? err.response.data : {}):null;
}catch(err){
console.error(err.message);
}
}
if(err.response && err.response.data === ''){
cbs.statusError.call(this, {status: err.response.status});
} else if (err.response && this.$$lib__.isObject(err.response.data)) {
cbs.statusError.call(this, err.response.data);
}else if(err.response){
cbs.requestError.call(this, err);
} else {
console.error('Error from ', '"'+path+'".', err.message);
}
reject(err);
});
});
} else {
this.$alert('您沒有權(quán)限請求該接口!', '請求錯誤', {
confirmButtonText: '確定',
type: 'warning'
});
}
};
核心代碼為cancelToken參數(shù)
var options = {
method: type,
url: path,
params: params,
headers: headers && typeof headers === 'object' ? headers : {},
cancelToken: new axios.CancelToken(function (cancel) {
Vue.Cancel && Vue.Cancel.push(cancel)
})
};
補充知識:problem:vue組件局部刷新,在組件銷毀(destroyed)時取消刷新無效問題
場景:
一個群發(fā)消息列表(數(shù)組)
列表下有多條消息(元素)
每條正在發(fā)送的消息數(shù)據(jù)狀態(tài)需要實時刷新,發(fā)送完成時需要顯示成功提示符合且不需要刷新,然后3秒消失。首次顯示列表時,已經(jīng)成功的狀態(tài)不顯示這個成功提示符。
1、定位確定采用局部刷新
2、進入消息列表請求獲取列表數(shù)據(jù)的接口,完成發(fā)送的消息不需顯示完成狀態(tài)
3、正在發(fā)送的消息首次渲染時就調(diào)用setTimeout輪詢刷新當(dāng)前消息的接口,完成時,顯示完成狀態(tài)(新增一個完成狀態(tài)的字段)
4、頁面銷毀時,還在發(fā)送的消息也取消刷新
誤區(qū):
1、每條消息沒有抽成一個單獨的組件,想要首次渲染組件調(diào)用刷新接口時,只能通過定義全局map變量來映射每條消息的刷新接口的定時器,明顯增加業(yè)務(wù)開發(fā)的復(fù)雜度,增加了一些不確定性的bug風(fēng)險。
每條消息抽成組件之后,就可以在組件中的mounted中去調(diào)用刷新的接口,頁面銷毀時取消刷新可以在destroyed里面去銷毀。
2、這里的一個誤區(qū)是在destroyed里面去清除定時器的id,導(dǎo)致調(diào)用了destroyed鉤子刷新的定時器還是無法清除。將定時器id當(dāng)做一個屬性值存在了每條數(shù)據(jù)所屬的對象中,然后在子組件(每條消息所屬的)中的destroyed中去讀取該對象的當(dāng)前的定時器屬性,因為讀出來是undifined,其實并沒有拿到當(dāng)前消息正在執(zhí)行的定時器,所以清除不掉。
組件使用有誤,每一個組件都是一個獨立的元素,其中定義的變量也是私有的,定時器id定在當(dāng)前組件的data中就可以了,不需要再在數(shù)組中的每一條消息中定一個專屬的定時器id。
抽象出來的簡單版刷新數(shù)據(jù),5秒后取消刷新。
let intervalId = null
function init() {
this.refresh()
}
function refresh() {
intervalId = setTimeout(() => {
this.getRefreshData()
}, 2000);
}
function getRefreshData() {
console.log('start get data.....', intervalId)
setTimeout(() => {
console.log('get data.....')
this.refresh()
}, 100);
}
function stopRefresh() {
console.log('stop....', intervalId)
clearInterval(intervalId)
}
this.init()
setTimeout(() => {
this.stopRefresh()
}, 5000);
以上這篇vue路由切換時取消之前的所有請求操作就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
element-plus/element-ui走馬燈配置圖片及圖片自適應(yīng)的最簡便方法
走馬燈功能在展示圖片時經(jīng)常用到,下面這篇文章主要給大家介紹了關(guān)于element-plus/element-ui走馬燈配置圖片及圖片自適應(yīng)的最簡便方法,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-03-03
Vuejs 用$emit與$on來進行兄弟組件之間的數(shù)據(jù)傳輸通信
本篇文章主要介紹了Vuejs 用$emit 與 $on 來進行兄弟組件之間的數(shù)據(jù)傳輸示例,非常具有實用價值,需要的朋友可以參考下。2017-02-02
vue使用?vue-socket.io三種方式及踩坑實例解析
這篇文章主要為大家介紹了vue使用?vue-socket.io三種方式及踩坑實例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-09-09

