UNPKG

ivue-material

Version:

A high quality UI components Library with Vue.js

155 lines (125 loc) 6.2 kB
const CLICK = 'click'; // 捕获实例 const captureInstances = Object.create(null); // 不捕获实例 const nonCaptureInstances = Object.create(null); // 实例列表 const instancesList = [captureInstances, nonCaptureInstances]; 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) { return instances[eventName].forEach(item); } Object.keys(instances).forEach(key); } // 捕获事件处理程序 const captureEventHandler = function onCaptureEvent (event) { /* eslint-disable-next-line babel/no-invalid-this */ commonHandler(this, captureInstances, event); }; // 非捕获事件处理程序 const nonCaptureEventHandler = function onNonCaptureEvent (event) { /* eslint-disable-next-line babel/no-invalid-this */ commonHandler(this, nonCaptureInstances, event); }; // 获取事件处理程序 const getEventHandler = function _getEventHandler (useCapture) { return useCapture ? captureEventHandler : nonCaptureEventHandler; }; export const directive = Object.defineProperties( {}, { // 初始化设置 bind: { value: function bind (el, binding) { // 判断参数 if (typeof binding.value !== 'function') { throw new TypeError('Binding value must be a function'); } // 传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。 const arg = binding.arg || CLICK; // 归并事件绑定 const normalisedBinding = { ...binding, ...{ arg, // 一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true } modifiers: { ...{ // 添加事件侦听器时使用 capture 模式 capture: false, // 阻止默认行为 prevent: false, // 调用 event.stopPropagation() 停止冒泡 stop: false }, ...binding.modifiers } } } const useCapture = normalisedBinding.modifiers.capture; // 实例化事件 const instances = useCapture ? captureInstances : nonCaptureInstances; // 判断事件中是否有对应的指令参数 初始化指令 if (!Array.isArray(instances[arg])) { instances[arg] = []; } if (instances[arg].push({ el, binding: normalisedBinding }) === 1) { if (typeof document === 'object' && document) { document.addEventListener(arg, getEventHandler(useCapture), useCapture); } } } }, // 指令与元素解绑时调用 unbind: { value: function bind (el) { // 比较元素 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) { // 查找元素实例 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 function install (Vue) { Vue.directive('click-outside', directive); }