vue路由切换时取消之前的所有请求操作


Posted in Javascript onSeptember 01, 2020

在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);

// 导入封装的回调函数
import {
 cbs,
 gbs
} from 'config/';

// 动态设置本地和线上接口域名
Vue.axios.defaults.baseURL = gbs.host;

/**
 * 封装axios的通用请求
 * @param {string} type get或post
 * @param {string} url 请求的接口URL
 * @param {object} data 传的参数,没有则传空对象
 * @param {object} urlParams url传参
 * @param {Function} fn 回调函数
 * @param {boolean} tokenFlag 是否需要携带token参数,为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)
 }) 
 };

 //检测接口权限
 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();
 }

 // 分发显示加载样式任务
 this.$store.dispatch('show_loading');

 if (tokenFlag !== true) {
  //如果你们的后台不会接受headers里面的参数,打开这个注释,即实现token通过普通参数方式传
  // 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 })
 // );
 // };
 //发送请求
 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('您没有权限请求该接口!', '请求错误', {
  confirmButtonText: '确定',
  type: 'warning'
 });
 }
};

核心代码为cancelToken参数

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)时取消刷新无效问题

场景:

一个群发消息列表(数组)

列表下有多条消息(元素)

每条正在发送的消息数据状态需要实时刷新,发送完成时需要显示成功提示符合且不需要刷新,然后3秒消失。首次显示列表时,已经成功的状态不显示这个成功提示符。

1、定位确定采用局部刷新

2、进入消息列表请求获取列表数据的接口,完成发送的消息不需显示完成状态

3、正在发送的消息首次渲染时就调用setTimeout轮询刷新当前消息的接口,完成时,显示完成状态(新增一个完成状态的字段)

4、页面销毁时,还在发送的消息也取消刷新

误区:

1、每条消息没有抽成一个单独的组件,想要首次渲染组件调用刷新接口时,只能通过定义全局map变量来映射每条消息的刷新接口的定时器,明显增加业务开发的复杂度,增加了一些不确定性的bug风险。

每条消息抽成组件之后,就可以在组件中的mounted中去调用刷新的接口,页面销毁时取消刷新可以在destroyed里面去销毁。

2、这里的一个误区是在destroyed里面去清除定时器的id,导致调用了destroyed钩子刷新的定时器还是无法清除。将定时器id当做一个属性值存在了每条数据所属的对象中,然后在子组件(每条消息所属的)中的destroyed中去读取该对象的当前的定时器属性,因为读出来是undifined,其实并没有拿到当前消息正在执行的定时器,所以清除不掉。

组件使用有误,每一个组件都是一个独立的元素,其中定义的变量也是私有的,定时器id定在当前组件的data中就可以了,不需要再在数组中的每一条消息中定一个专属的定时器id。

抽象出来的简单版刷新数据,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路由切换时取消之前的所有请求操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
键盘KeyCode值列表汇总
Nov 26 Javascript
判断及设置浏览器全屏模式
Apr 20 Javascript
js隐式全局变量造成的bug示例代码
Apr 22 Javascript
Bootstrap3制作搜索框样式的方法
Jul 11 Javascript
jQuery实现定位滚动条位置
Aug 05 Javascript
使用jQuery的load方法设计动态加载及解决被加载页面js失效问题
Mar 01 Javascript
jquery编写日期选择器
Mar 16 Javascript
JS+HTML5 FileReader实现文件上传前本地预览功能
Mar 27 Javascript
微信小程序 slot踩坑的解决
Apr 01 Javascript
Vue中keep-alive 实现后退不刷新并保持滚动位置
Mar 17 Javascript
javaScript Array api梳理
Mar 31 Javascript
Vue操作Storage本地化存储
Apr 29 Vue.js
jQuery实现动态加载瀑布流
Sep 01 #jQuery
vue Treeselect下拉树只能选择第N级元素实现代码
Aug 31 #Javascript
vue treeselect获取当前选中项的label实例
Aug 31 #Javascript
vue 监听 Treeselect 选择项的改变操作
Aug 31 #Javascript
搭建vscode+vue环境的详细教程
Aug 31 #Javascript
vue组件中实现嵌套子组件案例
Aug 31 #Javascript
vue 项目中当访问路由不存在的时候默认访问404页面操作
Aug 31 #Javascript
You might like
新手学PHP之数据库操作详解及乱码解决!
2007/01/02 PHP
php db类库进行数据库操作
2009/03/19 PHP
php装饰者模式简单应用案例分析
2019/10/23 PHP
javascript 获取图片颜色
2009/04/05 Javascript
javascript 读取XML数据,在页面中展现、编辑、保存的实现
2009/10/27 Javascript
js截取固定长度的中英文字符的简单实例
2013/11/22 Javascript
Javscript删除数组中指定元素并返回新数组
2014/03/06 Javascript
基于MVC5和Bootstrap的jQuery TreeView树形控件(二)之数据支持json字符串、list集合
2016/08/11 Javascript
Vue.js实现一个自定义分页组件vue-paginaiton
2016/09/05 Javascript
Servlet实现文件上传,可多文件上传示例
2016/12/05 Javascript
AngularJS中的按需加载ocLazyLoad示例
2017/01/11 Javascript
JS html时钟制作代码分享
2017/03/03 Javascript
zTree实现节点修改的实时刷新功能
2017/03/20 Javascript
Vue ElementUI之Form表单验证遇到的问题
2017/08/21 Javascript
Angular js 实现添加用户、修改密码、敏感字、下拉菜单的综合操作方法
2017/10/24 Javascript
JavaScript中关于class的调用方法
2017/11/28 Javascript
web前端vue实现插值文本和输出原始html
2018/01/19 Javascript
详解基于Vue2.0实现的移动端弹窗(Alert, Confirm, Toast)组件
2018/08/02 Javascript
优雅的elementUI table单元格可编辑实现方法详解
2018/12/23 Javascript
vue中 this.$set的用法详解
2019/09/06 Javascript
JS出现404错误原理及解决方案
2020/07/01 Javascript
Vue移动端项目实现使用手机预览调试操作
2020/07/18 Javascript
vue点击按钮实现简单页面的切换
2020/09/08 Javascript
Python3访问并下载网页内容的方法
2015/07/28 Python
python八大排序算法速度实例对比
2017/12/06 Python
Python基于TCP实现会聊天的小机器人功能示例
2018/04/09 Python
深入理解Django自定义信号(signals)
2018/10/15 Python
python+opencv打开摄像头,保存视频、拍照功能的实现方法
2019/01/08 Python
兰蔻法国官方网站:Lancôme法国
2020/02/22 全球购物
颇特女士香港官网:NET-A-PORTER香港
2021/03/08 全球购物
会计实习期自我鉴定
2013/10/06 职场文书
《海底世界》教学反思
2014/04/16 职场文书
2014最新实习证明模板
2014/10/02 职场文书
浅谈克隆 JavaScript
2021/11/02 Javascript
仅仅使用 HTML/CSS 实现各类进度条的方式汇总
2021/11/11 HTML / CSS
与Windows10相比Windows11有哪些改进?值不值得升级?
2021/11/21 数码科技