@58fe/p5
Version:
pc端vue组件
123 lines (114 loc) • 3.36 kB
JavaScript
// 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);
}