Element-ui 之 repeat-click 长按功能指令源码分析

此篇文章分析一下 element-ui 组件库中,repeat-click 指令的作用和源代码。

一. repeat-click 指令的应用

repeat-click 指令用于在用户在长按鼠标左键时,持续的执行其绑定的方法,直到用户抬起鼠标左键。

element-ui 组件库中,有两处应用到了:

  1. InputNumber 组件,在长按控制按钮(加号、减号)时,执行连续增加或减少。

在这里插入图片描述

  1. TimePicker 时间选择器组件,在长按上下箭头时,执行时间的切换。
    在这里插入图片描述

二. repeat-click 指令源码分析

2.1 repeat-click 源码实现思路

实现思路:

设定一个目标时间,用鼠标左键按下和抬起的持续时间与这个目标时间做对比:

  • 第一种情况是小于目标时间,那么就执行一次绑定的方法。
  • 第二种情况是大于目标时间,那么就以目标时间为间隔,持续的执行绑定的方法。

具体实现步骤:

  1. 在 vue 自定义指令的 bind 钩子中做处理,先设置间隔的时间,mac 为 100 毫秒,其余为 200 毫秒,然后将绑定的方法取出。
  2. 增加 mousedown 事件的监听,先去判断点击的是否为鼠标左键,如果不是,直接 return;如果是鼠标左键,则记录按下鼠标左键的时间,并且设置计时器,以目标时间为间隔持续的执行绑定的方法。
  3. 绑定鼠标的 mouseup 事件,判断如果鼠标抬起时间减去按下时间小于间隔时间,则执行一次绑定的方法。并且在 mouseup 时,还需要清除计时器,停止执行绑定的方法。

2.2 repeat-click 源码分析

export default {
  bind(el, binding, vnode) {
    // 设置计时器
    let interval = null;
    let startTime;
    // 每隔多长时间执行一次方法
    const maxIntervals = isMac() ? 100 : 200;
    // 绑定的方法
    const handler = () => vnode.context[binding.expression].apply();
    // 清除方法
    const clear = () => {
      // 小于间隔时间,则执行方法
      if (Date.now() - startTime < maxIntervals) {
        handler();
      }
      // 并且在鼠标抬起时清除计时器
      clearInterval(interval);
      interval = null;
    }
    on(el, 'mousedown', (e) => {
      // 如果点击的不是鼠标左键,则直接 return 
      if (e.button !== 0) return;
      // 变量 startTime 记录当前鼠标 mousedown 的时间
      startTime = Date.now();
      // 绑定鼠标 mouseup 事件,在 mouseup 事件时执行清除方法
      once(document, 'mouseup', clear);
      clearInterval(interval);
      // 每隔 maxIntervals 时间执行一次方法
      interval = setInterval(handler, maxIntervals);
    })
  }
}

涉及到的封装监听事件、以及移除监听事件的相关方法:

(1)on 方法:用于绑定监听事件,兼容 IE 浏览器

export const on = (function() {
  if (!isServer && document.addEventListener) {
    // 判断 document.addEventListener 是否存在,
    return function(element, event, handler) {
      // 如果元素、事件、回调方法都存在则绑定监听事件
      if (element && event && handler) {
        element.addEventListener(event, handler, false);
      }
    };
  } else {
    // 不存在,使用 attachEvent 兼容IE浏览器
    return function(element, event, handler) {
      if (element && event && handler) {
        element.attachEvent('on' + event, handler);
      }
    };
  }
})();

(2)off 方法:用于取消事件监听,兼容 IE 浏览器

export const off = (function() {
  if (!isServer && document.removeEventListener) {
    // 判断 document.removeEventListener 是否存在
    return function(element, event, handler) {
      // 如果元素、事件存在,则取消监听的绑定事件
      if (element && event) {
        element.removeEventListener(event, handler, false);
      }
    };
  } else {
    // 不存在,使用 detachEvent 兼容IE浏览器
    return function(element, event, handler) {
      if (element && event) {
        element.detachEvent('on' + event, handler);
      }
    };
  }
})();

(3)once 方法:用于监听绑定事件后,回调函数只触发一次

export const once = function(el, event, fn) {
  var listener = function() {
   // 如果传入了回调函数,则执行该函数
   if (fn) {
     fn.apply(this, arguments);
   }
   // 取消事件监听
   off(el, event, listener);
  };
  // 绑定事件监听
  on(el, event, listener);
};

三. InputNumber 组件使用该指令的具体情况

<template>
  <!-- 使用自定义指令 -->
  <span
    v-repeat-click="decrease"
  >
  </span>
</template>
<script>
  // 引入自定义指令
  import RepeatClick from '../../utils/directives/repeat-click';
  // 注册自定义指令
  export default {
    directives: {
      repeatClick: RepeatClick
    },
  }
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值