v-repeat-click 指令实现原理

160 阅读1分钟

该指令在el-input-number组件中使用。

当鼠标长按加号或者减号上,数字持续变化。这个效果就是使用v-repeat-click指令实现的。

源码

import { once, on } from 'element-ui/src/utils/dom';

export default {
  bind(el, binding, vnode) {
    let interval = null;
    let startTime;
    // VNode.context 拿到的是组件对象
    // apply 第一个参数不传,函数内部this指向window,改变函数内部this的指向,这么写的原因是什么??
    const handler = () => vnode.context[binding.expression].apply();
    const clear = () => {
      if (Date.now() - startTime < 100) {
        handler();
      }
      clearInterval(interval);
      interval = null;
    };

    on(el, 'mousedown', (e) => {
      // e.button是按下了鼠标的哪个键。不等于0则是说明按下的不是左键
      if (e.button !== 0) return;
      // Date 对象的静态方法。返回当前时间距离时间零点(1970年1月1日 00:00:00 UTC)的毫秒数
      startTime = Date.now();
      // 监听一次 mouseup 事件。在document上监听可以保证不管鼠标移到什么位置,只要抬起都可以执行
      once(document, 'mouseup', clear);
      clearInterval(interval);
      interval = setInterval(handler, 100);
    });
  }
};

其中这句的apply作用仍然不懂

const handler = () => vnode.context[binding.expression].apply();

on, off, once 函数

export const on = (function() {
  if (!isServer && document.addEventListener) {
    return function(element, event, handler) {
      if (element && event && handler) {
        element.addEventListener(event, handler, false);
      }
    };
  } else {
    return function(element, event, handler) {
      if (element && event && handler) {
        element.attachEvent('on' + event, handler);
      }
    };
  }
})();

export const off = (function() {
  if (!isServer && document.removeEventListener) {
    return function(element, event, handler) {
      if (element && event) {
        element.removeEventListener(event, handler, false);
      }
    };
  } else {
    return function(element, event, handler) {
      if (element && event) {
        element.detachEvent('on' + event, handler);
      }
    };
  }
})();

/* istanbul ignore next */
export const once = function(el, event, fn) {
  var listener = function() {
    if (fn) {
      fn.apply(this, arguments);
    }
    off(el, event, listener);
  };
  on(el, event, listener);
};