理论上可以用于任何元素,生效时会在元素上出现一个同大小的灰色蒙层(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 利用指令实现禁止反复发送请求的更多相关文章

  1. Vue 利用指令实现禁止反复发送请求

    前端做后台管控系统,在某些接口请求时间过长的场景下,需要防止用户反复发起请求. 假设某场景下用户点击查询按钮后,后端响应需要长时间才能返回数据.那么要规避用户返回点击查询按钮无外乎是让用户无法在合理时 ...

  2. Vue项目中使用Vuex + axios发送请求

    本文是受多篇类似博文的影响写成的,内容也大致相同.无意抄袭,只是为了总结出一份自己的经验. 一直以来,在使用Vue进行开发时,每当涉及到前后端交互都是在每个函数中单独的写代码,这样一来加大了工作量,二 ...

  3. vue自定义指令,比onerror更优雅的方式实现当图片加载失败时使用默认图,提供三种方法

    首先,来看下效果图(演示一下图片正常加载与加载失败时的效果) 在线体验地址:https://hxkj.vip/demo/vueImgOnerror/ 一.常规方法解决 我们都知道,img标签支持one ...

  4. vue之指令

    一.什么是VUE? 它是构建用户界面的JavaScript框架(让它自动生成js,css,html等) 二.怎么使用VUE? 1.引入vue.js 2.展示HTML <div id=" ...

  5. vue自定义指令clickoutside使用以及扩展用法

    vue自定义指令clickoutside使用以及扩展用法 产品使用vue+element作为前端框架.在功能开发过程中,难免遇到使用element的组件没办法满足特殊的业务需要,需要对其进行定制,例如 ...

  6. vue自定义指令clickoutside扩展--多个元素的并集作为inside

    都是个人理解,如果发现错误,恳请大家批评指正,谢谢.还有我说的会比较啰嗦,因为是以自身菜鸡水平的视角来记录学习理解的过程,见谅. 1.前言 产品使用vue+element作为前端框架.在功能开发过程中 ...

  7. vue 自定义指令的魅力

    [第1103期]vue 自定义指令的魅力 点点 前端早读课 2017-11-08 前言 很多事情不能做过多的计划,因为计划赶不上变化.今日早读文章由富途@点点翻译分享. 正文从这开始- 在你初次接触一 ...

  8. Vue的指令和成员

    目录 Vue的指令和成员 指令 表单 斗篷 条件 循环 成员 计算成员 监听成员 Vue的指令和成员 指令 表单 表单指令一般是和属性指令联合使用的,最常见的就是v-model="变量&qu ...

  9. vue自定义指令实例使用(实例说明自定义指令的作用)

    在写vue项目的时候,我们经常需要对后台返回的数据进行大量的渲染操作,其中就包含了大量的对特殊数据的进一步处理,比如说时间戳.图片地址.特殊数据显示等等特殊数据处理改进. 其实遇到这种情况,通过Vue ...

随机推荐

  1. FastReport快速实现条形码,二维码面单打印

    一.什么是FastReport? FastReport是功能齐全的报表控件,使开发者可以快速并高效地为·NET/VCL/COM/ActiveX应用程序添加报表支持. FastReport有很多产品,如 ...

  2. python编译器的安装和pycharm的安装

    python编译器的安装 进入官网https://www.python.org/,根据提示安装 安装python编译器 pychram安装 下载地址: https://www.jetbrains.co ...

  3. Flask解析(一):Local、LocalStak、LocalProxy

    原创作者:flowell,转载请标明出处:https://www.cnblogs.com/flowell/p/local_local_proxy_local_stack.html Local是什么? ...

  4. Dubbo 优雅停机演进之路

    一.前言 在 『ShutdownHook- Java 优雅停机解决方案』 一文中我们聊到了 Java 实现优雅停机原理.接下来我们就跟根据上面知识点,深入 Dubbo 内部,去了解一下 Dubbo 如 ...

  5. 一个普通类就能干趴你的springboot,你信吗?

    先声明本人并不是标题党,如果看了本篇文章并且认为没有得到任何收获,请您随便留言骂我,本人绝不还口,已经对springboot了如指掌大大神,求放过! 不BB了,直接上代码,请各位在自己的springb ...

  6. git push 报src refspec xxx does not match any的错误

    今天在向一个新的远程分支上推送项目的时候报错: 远程分支branch_new是其他人建的,我在自己本地修改后把自己分支的修改推送到这个远程分支上. 把修改提到本地仓库: git add ./ git ...

  7. Redis开发与运维:SDS

    STRING 我们会经常打交道的string类型,在redis中拥有广泛的使用.也是开启redis数据类型的基础. 在我最最开始接触的redis的时候,总是以为字符串类型就是值的类型是字符串. 比如: ...

  8. python——自行实现sorted函数

    仿照内建函数sorted,自行实现一个sort函数,能够为列表进行排序 看下面实例的前提是掌握 0.掌握sorted函数的用法.1.函数基本概念.2.函数是如何传参的.3.掌握三元表达式.4.掌握内建 ...

  9. 在VMware环境下安装CentOS7

    1. 软件准备: 推荐使用VMware,在这里我使用的是VMware15 映像:可以去官网下载,没有的话也可以在下方链接里下载 链接:https://pan.baidu.com/s/1r_7K-UI0 ...

  10. Elasticsearch生产环境遇到的问题以及解决方案

    Elasticsearch是一个开源的分布式实时搜索与分析引擎,支持云服务.它是基于Apache Lucene搜索引擎的类库创建的,提供了全文搜索能力.多语言支持.专门的查询语言.支持地理位置服务.基 ...