更好一点的: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滚动并且本身也会有动条的元素,等下一个项目去实践一下脑子里的想法。

原文地址:https://www.cnblogs.com/youyouluo/p/11971431.html

时间: 2024-10-13 13:22:43

更好一点的:Vue 利用指令实现禁止反复发送请求的相关文章

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

前端做后台管控系统,在某些接口请求时间过长的场景下,需要防止用户反复发起请求. 假设某场景下用户点击查询按钮后,后端响应需要长时间才能返回数据.那么要规避用户返回点击查询按钮无外乎是让用户无法在合理时间内再次点击按钮.实现方式也有好几种: 1.在按钮点击发起请求后,弹个蒙层,显示个loading,等请求数据返回了将蒙层隐藏掉. 2.在按钮点击发起请求后,将按钮禁用掉,同样等数据返回了将按钮禁用解除. 以上是比较常见的2种方案. 实现上最简单的肯定是在需要的页面种在请求前和拿到数据后,单独处理.这

vue自定义指令

什么是指令? 指令 (Directives) 是带有 v- 前缀的特殊属性. 它可以写在DOM元素上,对html进行操作.常用的指令比如有:v-if,v-else,v-show,v-for等.这些都是官方直接给定的,另外Vue也允许注册自定义指令,有时这很有用. 自定义指令方法 自定义一个指令很简单,官网给出一个简单的例子,自定义一个聚焦指令v-focus: // 注册一个全局自定义指令 `v-focus` Vue.directive('focus', { // 当被绑定的元素插入到 DOM 中

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

vue自定义指令clickoutside使用以及扩展用法 产品使用vue+element作为前端框架.在功能开发过程中,难免遇到使用element的组件没办法满足特殊的业务需要,需要对其进行定制,例如要求选择器的弹出框中,增加搜索过滤(跟目前element的输入建议不太一样).于是想说说之前修改element组件,并定制为业务组件过程中遇到的问题. ps:因为对某些组件改动很大,所以是直接拷贝了一份源码,然后再进行修改,但是这样会遇到挺多问题,建议对于vue组件如果改动不大,只是简单功能扩展,就

vue自定义指令directive

vue中指令分为全局指令和局部指令 先来看全局自定义指令: 第一个参数是指令的名字,第二个参数可以是函数也可以是对象,先来看函数: 函数中接收三个参数: el在这里是input元素 bindings里是一些绑定信息: 其中expression是指绑定的变量名字,这里是content name是指令名字 value是绑定数据的值,上面content为空,所以目前value为空 v-slice上还可以写修饰符 还可以传参: vnode虚拟节点: vnode中contex是vue实例,其中的conte

Vue的指令和成员

目录 Vue的指令和成员 指令 表单 斗篷 条件 循环 成员 计算成员 监听成员 Vue的指令和成员 指令 表单 表单指令一般是和属性指令联合使用的,最常见的就是v-model="变量",这种情况下绑定的变量所控制的就是表单元素的实际value值,我们可以用这种方法来实现实时同步一些input框的内容,以及单一复选框和多个复选框的设置,如下例 <body> <div id="app"> <form action=""

懂一点前端—Vue快速入门

01. 什么是 Vue Vue (读音 /vju?/,类似于 view) 是一套用于构建用户界面的渐进式框架,是当下很火的一个 JavaScript MVVM 库,是以 数据驱动和组件化 的思想构建的. MVVM 模式简述 下图不仅概括了 MVVM 模式 (Model-View-ViewModel),还描述了在 Vue.js 中 ViewModel 是如何和 View 以及 Model 进行交互的. ViewModel 是 Vue.js 的核心,它是一个 Vue 实例.Vue 实例是作用于某一个

vue之指令篇 ps简单的对比angular

这两天在开始vue的大型项目,发现和ng还是有许多不同,这里对比下两者的指令系统 难度系数:ng的指令难度大于vue:至少vue上暂时没发现@&=:require,compile,precompile,postcompile之类的小型地雷... 这篇文章只看表象:何为指令?这里借助ng的解释来解释vue,就是当你的项目中,需要一些dom操作,并且MVMM自带的事件指令感觉麻烦的时候,可以把一些dom操作封装到一个公共方法,这就是指令,大概用在vue上也可以说个70%: 写法,vue: Vue.d

为什么知乎上很多人都反对创业?(上战场的士兵如果先拿枪打打靶练练枪法,研究研究战术之后,战损比肯定要更好看一点)

为什么知乎上很多人都反对创业? 经常看到一些排名靠前的答案,内容无非规劝他人不要创业,要脚踏实地,认为党和国家大众创业万众创新的政策方针都是胡扯?难道知乎上的知识分子们竟比国家的智囊更有远见?还是他们的认识层次达不到? 著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:唐缺链接:https://www.zhihu.com/question/37559307/answer/72755062来源:知乎 -------------------------------------

vue的指令

我之前学了学angular 发现angular和vue的指令有点类似 先说一下 new  Vue({ el: "#box", // element(元素) 当前作用域 data(){ return { //用return返回对象 msg: "122" } } }) 首先是 v-model双向绑定数据 <input type="text" v-model="msg"/>   {{msg}} <!--取数据--&