ivue-material-plus
Version:
A high quality UI components Library with Vue.js
175 lines (145 loc) • 4.62 kB
text/typescript
const CLICK = 'click';
// 捕获实例
const captureInstances = Object.create(null);
// 不捕获实例
const nonCaptureInstances = Object.create(null);
// 实例列表
const instancesList = [captureInstances, nonCaptureInstances];
/**
* The common event handler for bot capture and non-capture events.
*
* @param {!Object} context - The event context.
* @param {!Object} instances - The capture or non-capture registered instances.
* @param {Event} event - The event object.
* @returns {undefined} Default.
*/
const commonHandler = function _onCommonHandler(context, instances, event) {
const { target } = event;
const item = function _item(item) {
const { el } = item;
if (el !== target && !el.contains(target)) {
const { binding } = item;
if (binding.modifiers.stop) {
event.stopPropagation();
}
if (binding.modifiers.prevent) {
event.preventDefault();
}
binding.value.call(context, event);
}
};
const key = function _key(eventName: string) {
return instances[eventName].forEach(item);
};
Object.keys(instances).forEach(key);
};
// 捕获事件处理程序
const captureEventHandler = function onCaptureEvent(event) {
commonHandler(this, captureInstances, event);
};
// 非捕获事件处理程序
const nonCaptureEventHandler = function onNonCaptureEvent(event) {
commonHandler(this, nonCaptureInstances, event);
};
// 获取事件处理程序
const getEventHandler = function _getEventHandler(useCapture: boolean) {
return useCapture ? captureEventHandler : nonCaptureEventHandler;
};
// 指令定义
function inserted(el: Element, binding: Record<string, any>): void {
// 判断参数
if (typeof binding.value !== 'function') {
throw new TypeError('Binding value must be a function');
}
// 事件名称
let eventType;
const modifiers = binding.modifiers;
if (modifiers.click) {
eventType = 'click';
} else if (modifiers.mousedown) {
eventType = 'mousedown';
} else if (modifiers.touchstart) {
eventType = 'touchstart';
} else {
eventType = CLICK;
}
// 是否开启外部点击的 capture 模式,可通过全局配置
const useCapture = binding.arg;
// 归并事件绑定
const normalisedBinding = {
...binding,
...{
// 一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
modifiers: {
...{
// 添加事件侦听器时使用 capture 模式
capture: false,
// 阻止默认行为
prevent: false,
// 调用 event.stopPropagation() 停止冒泡
stop: false,
},
...binding.modifiers,
},
},
};
// 实例化事件
const instances = useCapture ? captureInstances : nonCaptureInstances;
// 判断事件中是否有对应的指令参数 初始化指令
if (!Array.isArray(instances[eventType])) {
instances[eventType] = [];
}
if (
instances[eventType].push({
el,
binding: normalisedBinding,
}) === 1
) {
if (typeof document === 'object' && document) {
document.addEventListener(
eventType,
getEventHandler(useCapture),
useCapture
);
}
}
}
// 指令与元素解绑时调用
function unbind(el: Element): void {
// 比较元素
const compareElements = function _compareElements(item) {
return item.el !== el;
};
const instances = function _instances(instances) {
// 实例key
const instancesKeys = Object.keys(instances);
// 判断是否有实例
if (instancesKeys.length) {
// 判断是否使用事件捕获
const useCapture = instances === captureInstances;
const keys = function _keys(eventName: string) {
// 查找元素实例
const newInstance = instances[eventName].filter(compareElements);
if (newInstance.length) {
instances[eventName] = newInstance;
} else {
if (typeof document === 'object' && document) {
// 移除事件
document.removeEventListener(
eventName,
getEventHandler(useCapture),
useCapture
);
}
delete instances[eventName];
}
};
instancesKeys.forEach(keys);
}
};
instancesList.forEach(instances);
}
export default {
beforeMount: inserted,
unmounted: unbind,
};