• 更好一点的: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滚动并且本身也会有动条的元素,等下一个项目去实践一下脑子里的想法。
  • 相关阅读:
    单片机I/O口推挽与开漏输出详解(力荐)
    wifi
    SDIO总线协议
    [hi3521] nand flash 的 boot 启动模式的区别?
    常见SOC启动流程分析
    PWM通过RC低通滤波器模拟DAC
    海思 core 电压动态调整
    USB线上/串口/I2C引脚串联电阻的作用
    几种flash存储芯片的用途和分类
    示波器分析I2C时序波形图
  • 原文地址:https://www.cnblogs.com/youyouluo/p/11971431.html
Copyright © 2020-2023  润新知