UNPKG

@58fe/p5

Version:

pc端vue组件

123 lines (114 loc) 3.36 kB
// https://github.com/Xotic750/v-click-outside-x const CLICK = 'click'; const captureInstances = Object.create(null); const noCaptureInstances = Object.create(null); const instancesList = [ captureInstances, noCaptureInstances ]; // 判断点击的是外部区域 调起方法 const commonHandler = function(context, instance, event) { const { target } = event; const itemIterator = function(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 keysIterator = function(eventName) { return instance[eventName].forEach(itemIterator); }; Object.keys(instance).forEach(keysIterator); }; const captureEventHandler = function(event) { commonHandler(this, captureInstances, event); }; const noCaptureEventHandler = function(event) { commonHandler(this, noCaptureInstances, event); }; const getEventHandler = function(useCapture) { return useCapture ? captureEventHandler : noCaptureEventHandler; }; export const directive = Object.defineProperties( {}, { bind: { /** * el 目标节点dom元素 * binding 参数详细 * example: v-click-outside:click.stop="onClickOutside" * { arg: "click" def: {bind: ƒ, unbind: ƒ} expression: "onClickOutside" modifiers: {stop: true} name: "click-outside" rawName: "v-click-outside:click.stop" value: ƒ () } */ value: function bind(el, binding) { if (typeof binding.value !== 'function') { throw new TypeError('Binding value must be a function'); } const arg = binding.arg || CLICK; const normalisedBinding = Object.assign( {}, binding, { arg, modifiers: { capture: false, prevent: false, stop: false } }, { modifiers: binding.modifiers } ); const useCapture = normalisedBinding.modifiers.capture; const instance = useCapture ? captureInstances : noCaptureInstances; if (!Array.isArray(instance[arg])) { instance[arg] = []; } if (instance[arg].push({ el, binding: normalisedBinding }) === 1) { if (document && typeof document === 'object') { document.addEventListener(arg, getEventHandler(useCapture), useCapture); } } } }, unbind: { value: function unbind(el) { const compareElements = (item) => { return item.el !== el; }; instancesList.forEach((instances) => { const instanceKeys = Object.keys(instances); // ['click', 'mousedown'] if (instanceKeys.length) { const useCapture = instances === captureInstances; const keysIterator = function(eventName) { const newInstance = instances[eventName].filter(compareElements); if (newInstance.length) { instances[eventName] = newInstance; } else { if (document && typeof document === 'object') { document.removeEventListener(eventName, getEventHandler(useCapture), useCapture); } } delete instances[eventName]; }; instanceKeys.forEach(keysIterator); } }); } } } ); export function install(Vue) { Vue.directive('click-outside', directive); }