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 源码分析

js 复制代码
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 浏览器

js 复制代码
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 浏览器

js 复制代码
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 方法:用于监听绑定事件后,回调函数只触发一次

js 复制代码
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 组件使用该指令的具体情况

html 复制代码
<template>
  <!-- 使用自定义指令 -->
  <span
    v-repeat-click="decrease"
  >
  </span>
</template>
<script>
  // 引入自定义指令
  import RepeatClick from '../../utils/directives/repeat-click';
  // 注册自定义指令
  export default {
    directives: {
      repeatClick: RepeatClick
    },
  }
</script>
相关推荐
i220818 Faiz Ul30 分钟前
智慧养老平台|基于SprinBoot+vue的智慧养老平台系统(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·毕设·智慧养老平台
Lkstar35 分钟前
Pinia 进阶:Setup Store、插件系统与状态持久化,一篇全搞懂
前端·vue.js
Nikluas37 分钟前
彻底搞懂 Vue 运行时的四大核心谜题:Render、Effect、Diff 算法与 Block Tree 演进
vue.js·面试
Aolith39 分钟前
手机端刷新总是 404?你需要知道 SPA Fallback 规则
前端·vue.js
zyl837211 小时前
RDKit.js + Vue3快速上手
javascript·vue.js·ecmascript
木易 士心2 小时前
Vue 事件总线(EventBus)详解
javascript·vue.js
海兰2 小时前
【实用程序】图片处理服务,前端应用 (Vue 3 + Pinia + Vite)后端服务 (Node.js + Express + Sharp)
前端·javascript·vue.js·node.js·pinia
m0_502724953 小时前
vue3生成pdf
前端·javascript·vue.js·pdf
Liu.7743 小时前
Vue3结合Element Plus封装点击查看大图的自定义指令
javascript·vue.js·elementui
代码煮茶17 小时前
Vite 5.0 新特性深度解析:更快、更干净、更未来的前端构建利器
vue.js