更好一点的:Vue 利用指令实现禁止反复发送请求
理论上可以用于任何元素,生效时会在元素上出现一个同大小的灰色蒙层(button元素会该表原生的disabled属性)。
/**
* 当元素触发发起请求后,当发起的请求中最后一个请求的结果返回(不关心返回顺序和结果),解锁元素禁用。
* 优化:用一个pending记录所有请求,逐个判定是否返回结果。
* 指令的方式使用轮询去校验接口是否返回结果,也可以在axios拦截器中,改变store中的数据,
* 然后在页面的computed中处理,不过页面内代码不如一个指令来的方便。
* 也可以用Bus来代替轮询
*/
const forbiddenInterval = 200; /**
* 配合ElementUI逐次查找父节点,目前仅考虑 body 和 dialogue 2个场景
* 将目标节点设为root,将mask(非button元素,el-button实际上就是个原生button元素,直接用原生属性disabled即可)挂在root下
* 并且相对root定位
*/
function findRootTag(el) {
let parent = el.parentNode;
let type = null;
let root = null;
while (parent) {
if (parent.tagName === 'BODY') {
type = 'body';
root = parent;
break;
} else if (parent.getAttribute('role') === 'dialog') {
type = 'dialog';
root = parent;
break;
}
parent = parent.parentNode;
}
return { type, root };
} export default {
inserted(el) {
el.timer = null;
if (el.tagName === 'BUTTON') {
el.forbiddenClick = () => {
el.disabled = true;
el.classList.add('is-disabled');
el.timer = setInterval(() => {
if (window.currentResq.done) {
clearInterval(el.timer);
el.disabled = false;
el.classList.remove('is-disabled');
}
}, forbiddenInterval);
};
el.addEventListener('click', el.forbiddenClick);
} else {
const { type, root} = findRootTag(el);
let mask = document.createElement('div');
if (type === 'dialog') {
/* dialog上的mask z-index 设置的较大 */
mask.setAttribute('style',
`
position: absolute;
diplay: none;
background-color: #e4e7ed;
cursor: not-allowed;
opacity: .4;
z-index: 9999;
`
);
} else {
mask.setAttribute('style',
`
position: absolute;
diplay: none;
background-color: #e4e7ed;
cursor: not-allowed;
opacity: .4;
z-index: 1000;
`
);
} mask.classList.add('mask');
root.appendChild(mask);
el.instance = mask;
el.root = root;
el.type = type;
}
},
update(el, binding) {
if (el.tagName !== 'BUTTON' && binding.value !== binding.oldValue) {
const root = el.root;
const type = el.type;
const scrollTop = root.scrollTop || document.documentElement.scrollTop;
const scrollLeft = root.scrollLeft || document.documentElement.scrollLeft;
const mask = el.instance;
const elRect = el.getBoundingClientRect();
mask.style.width = `${elRect.width}px`;
mask.style.height = `${elRect.height}px`;
if (type === 'body') {
mask.style.top = `${elRect.top + scrollTop}px`;
mask.style.left = `${elRect.left + scrollLeft}px`;
} else if (type === 'dialog') {
const rootRect = root.getBoundingClientRect();
mask.style.top = `${elRect.top - rootRect.top}px`;
mask.style.left = `${elRect.left - rootRect.left}px`;
}
mask.style.display = 'block'; el.timer = setInterval(() => {
if (window.currentResq.done) {
clearInterval(el.timer);
mask.style.display = 'none';
}
}, forbiddenInterval);
}
},
unbind(el) {
if (el.instance) {
el.root.removeChild(el.instance);
}
if (el.forbiddenClick) {
document.removeEventListener('click', el.forbiddenClick);
}
},
};
还有很多可以改进的地方,比如应该是有办法去兼容dialog这种会禁用body滚动并且本身也会有动条的元素,等下一个项目去实践一下脑子里的想法。
更好一点的:Vue 利用指令实现禁止反复发送请求的更多相关文章
- Vue 利用指令实现禁止反复发送请求
前端做后台管控系统,在某些接口请求时间过长的场景下,需要防止用户反复发起请求. 假设某场景下用户点击查询按钮后,后端响应需要长时间才能返回数据.那么要规避用户返回点击查询按钮无外乎是让用户无法在合理时 ...
- Vue项目中使用Vuex + axios发送请求
本文是受多篇类似博文的影响写成的,内容也大致相同.无意抄袭,只是为了总结出一份自己的经验. 一直以来,在使用Vue进行开发时,每当涉及到前后端交互都是在每个函数中单独的写代码,这样一来加大了工作量,二 ...
- vue自定义指令,比onerror更优雅的方式实现当图片加载失败时使用默认图,提供三种方法
首先,来看下效果图(演示一下图片正常加载与加载失败时的效果) 在线体验地址:https://hxkj.vip/demo/vueImgOnerror/ 一.常规方法解决 我们都知道,img标签支持one ...
- vue之指令
一.什么是VUE? 它是构建用户界面的JavaScript框架(让它自动生成js,css,html等) 二.怎么使用VUE? 1.引入vue.js 2.展示HTML <div id=" ...
- vue自定义指令clickoutside使用以及扩展用法
vue自定义指令clickoutside使用以及扩展用法 产品使用vue+element作为前端框架.在功能开发过程中,难免遇到使用element的组件没办法满足特殊的业务需要,需要对其进行定制,例如 ...
- vue自定义指令clickoutside扩展--多个元素的并集作为inside
都是个人理解,如果发现错误,恳请大家批评指正,谢谢.还有我说的会比较啰嗦,因为是以自身菜鸡水平的视角来记录学习理解的过程,见谅. 1.前言 产品使用vue+element作为前端框架.在功能开发过程中 ...
- vue 自定义指令的魅力
[第1103期]vue 自定义指令的魅力 点点 前端早读课 2017-11-08 前言 很多事情不能做过多的计划,因为计划赶不上变化.今日早读文章由富途@点点翻译分享. 正文从这开始- 在你初次接触一 ...
- Vue的指令和成员
目录 Vue的指令和成员 指令 表单 斗篷 条件 循环 成员 计算成员 监听成员 Vue的指令和成员 指令 表单 表单指令一般是和属性指令联合使用的,最常见的就是v-model="变量&qu ...
- vue自定义指令实例使用(实例说明自定义指令的作用)
在写vue项目的时候,我们经常需要对后台返回的数据进行大量的渲染操作,其中就包含了大量的对特殊数据的进一步处理,比如说时间戳.图片地址.特殊数据显示等等特殊数据处理改进. 其实遇到这种情况,通过Vue ...
随机推荐
- 爬虫链接mongodb 以及多线程多进程的操作
一.连接mongodb 1. 设置数据库 client=pymongo.MongoClient(‘localhost’) 2. db=client[‘lag ...
- java中Arrays.sort()对二位数组进行排序
int [][]a = new int [5][2]; //定义一个二维数组,其中所包含的一维数组具有两个元素 对于一个已定义的二位数组a经行如下规则排序,首先按照每一个对应的一维数组第一个元素进行升 ...
- mysql中的锁机制之悲观锁和乐观锁
1.悲观锁? 悲观锁顾名思义就是很悲观,悲观锁认为数据随时就有可能会被外界进行修改,所以悲观锁一上来就会把数据给加上锁.悲观锁一般都是依靠关系型数据库提供的锁机制,然而事实上关系型数据库中的行锁,表锁 ...
- 真正的打包scrapy单文件(不包含cfg)
前置:https://www.cnblogs.com/luocodes/p/11827850.html 解决最后一个问题,如何将scrapy真正的打包成单文件 耗了一晚上时间,今天突然有灵感了 错误分 ...
- 基于canvas的流程编辑器
今年由于项目上需要给客户的流程管理系统进行升级,其中包含流程的可视化.于是在网上找一些可以用的轮子,考察了D3,js.GooFlow.js.G6-Editor等工具后,发现D3,js学习成本太高,G6 ...
- Elasticsearch6.x集群部署
一.准备阶段 三台ubuntu系统机器 ip 计算机名 192.168.2.132 master 192.168.2.133 slave1 192.168.2.134 slave2 下载: jdk-8 ...
- 你真的会写单测吗?TDD初体验
前言: 昨天读到了一篇文章,讲的是TDD,即Test-Driven Development,测试驱动开发.大体意思是,它要求在编写某个功能的代码之前先编写测试代码,然后只编写使测试通过的功能代码,通过 ...
- vue登录功能和将商品添加至购物车实现
2.1: 学子商城--用户登录 用户登录商城用户操作行为,操作用户输入用户名和密码 点击登录按钮,一种情况登录成功 一种情况登录失败 "用户名或密码有误请检查" 2.2:如何实现 ...
- PowerMock学习(一)之PoweMock的入门--模拟新增学生操作
关于powermock 在TDD领域Mock框架有很多,比如EasyMock,JMock,Mockito.可能有些同学会好奇了,为什么要重点把powermock拿出来呢,因为powermock可以解决 ...
- map集合中哪些是线程安全的
为什么HashMap是线程不安全的 总说 HashMap 是线程不安全的,不安全的,不安全的,那么到底为什么它是线程不安全的呢?要回答这个问题就要先来简单了解一下 HashMap 源码中的使用的存储结 ...