ElementUI 源码解析之计数器

826 阅读2分钟

谈到该组件就很有意思呢,因为需要自定义Vue指令,这是计数器的核心代码也是最难代码下面我们来看看吧

前面那两个span分别代表了加和减 值得注意的是用到了我们从来没有用过的一个指令

v-repeat-click

大家看到了吧是自定义vue指令,局部引入的,那现在我们来看看是怎么写的吧

有关于Vue自定义知识请访问Vue官网这里不做过多介绍

1.首先初始化定时器和startTime

2.vnode.context获取vue上下文,binding.expression指的是在这里指定的是传递进来的函数,这里就是执行那个函数

3.clear函数简单的来说就是判断是否达到预期时间,达到就执行2步骤函数

4.用户如果触发了mousedown就会执行下面内容会调用once外部方法

5 执行定时器定时执行

once源码解析

import Vue from 'vue';
const isServer = Vue.prototype.$isServer;
export default {
	bind(el, binding, vnode) {
		let interval = null;
		let startTime;
		const handler = () => vnode.context[binding.expression].apply();
		const clear = () => {
			if (Date.now() - startTime < 1000) {
				handler();
			}
			clearInterval(interval);
			interval = null;
		};
		on(el, 'mousedown', (e) => {
			console.log('mousedown')
			if (e.button !== 0) {
				return
			}
			startTime = Date.now()
			once(document, 'mouseup', clear);
			clearInterval(interval);
			console.log("清楚定时器")
			interval = setInterval(handler, 1000);
		})
	}
}
const once = function(el, event, fn) {
	var listener = function() {
		if (fn) {
			fn.apply(this, arguments);
		}
		off(el, event, listener);
	};
	on(el, event, listener);
};
const on = (function() {
	if (!isServer && document.addEventListener) {
		return function(element, event, handler) {
			console.log(handler);
			if (element && event && handler) {
				console.log("clear开始执行了")
				element.addEventListener(event, handler, false);
			}
		};
	} else {
		return function(element, event, handler) {
			if (element && event && handler) {
				element.attachEvent('on' + event, handler);
			}
		};
	}
})(); /* istanbul ignore next */
const off = (function() {
	if (!isServer && document.removeEventListener) {
		return function(element, event, handler) {
			console.log(handler);
			if (element && event) {
				element.removeEventListener(event, handler, false);
			}
		};
	} else {
		return function(element, event, handler) {
			if (element && event) {
				element.detachEvent('on' + event, handler);
			}
		};
	}
})();

下面来讲一下整个执行流程

1.用户按下鼠标后判断是不是左键如果是加入下一步

2.赋值初始化startTime

3.调用once后清除定时器最后执行解绑事件和重新绑定事件 "mouseup"

4.定时器执行直到松开鼠标做左键被触发清除定时器

最后一点:once方法的第一个参数是document,这个也很关键,你可能以为在加减按钮上绑定onmousedown就应该在加减按钮上绑定onmouseup,这样做就会出bug,考虑一种情况,当你鼠标在加减按钮上按下时,然后移动鼠标到按钮外,再放开鼠标,此时会发现数字还在增加,这就是bug,因此要在document这个最外层的dom元素上绑定mouseup,这样mouseup事件总能被响应,否则乱移动鼠标就会造成数字一直增加

总结:其实这些代码是我最浅显直观的认识希望各位大牛多多提一些建议,没想到就这几行代码实现了一个看似复杂的功能,确实有趣,确实很酷,once函数简单的来说是一个观察者模式:当一个对象的状态发生变化时,能够自动通知其他关联对象,继续加油冲冲冲!