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>
相关推荐
TT哇2 小时前
【实习 】银行经理端两个核心功能的开发与修复(银行经理绑定逻辑修复和线下领取扫码功能开发)
java·vue.js
星光不问赶路人3 小时前
vue3使用jsx语法详解
前端·vue.js
weixin79893765432...4 小时前
Vue 组件的更新过程(编译系统 + 响应式系统 + 虚拟 DOM & Diff)
vue.js
我是伪码农5 小时前
Vue 智慧商城项目
前端·javascript·vue.js
小书包酱6 小时前
在 VS Code中,vue2-vuex 使用终于有体验感增强的插件了。
vue.js·vuex
Zhencode6 小时前
Vue3 响应式依赖收集与更新之effect
前端·vue.js
天下代码客6 小时前
使用electronc框架调用dll动态链接库流程和避坑
前端·javascript·vue.js·electron·node.js
weixin79893765432...7 小时前
Vue 渲染体系“三件套”(template 模板语法、h 函数和 JSX 语法)
vue.js·h函数·template 模板·jsx 语法
xkxnq8 小时前
第五阶段:Vue3核心深度深挖(第74天)(Vue3计算属性进阶)
前端·javascript·vue.js
Hilaku8 小时前
不要在简历上写精通 Vue3?来自面试官的真实劝退
前端·javascript·vue.js