Skip to content

Instantly share code, notes, and snippets.

@Lavrend
Last active June 9, 2021 09:16
Show Gist options
  • Save Lavrend/10876e54c0aed7afe9a1e0c3e75d8349 to your computer and use it in GitHub Desktop.
Save Lavrend/10876e54c0aed7afe9a1e0c3e75d8349 to your computer and use it in GitHub Desktop.
The directive responds to click outside the block
/**
* The directive responds to click outside the block
* @example <my-component v-click-outside="callback" />
*/
const events = ['click'];
const instances = new Map();
const onClickOutside = ({ event, el, handler, middleware }) => {
const isClickOutside = event.target !== el && !el.contains(event.target);
if (!isClickOutside || !middleware(event, el)) return null;
return handler(event, el);
};
//Requires loop to toggle events for several listeners of an element
const toggleEventListeners = (eventHandlers) => {
return (action) => {
eventHandlers.forEach(({ event, handler }) => {
document[`${action}EventListener`](event, handler, true);
});
};
};
//Validator function
const processArgs = (value) => {
const isFunction = typeof value === 'function';
if (!isFunction && typeof value !== 'object') {
throw new Error(`v-click-outside: Binding value should be a function or an object, ${typeof value} given`);
}
return {
handler: isFunction ? value : value.handler,
middleware: value.middleware || (() => true)
};
};
//Now need adapter to handle several events for one Map element
const eventAdapter = (events, { el, handler, middleware }) => {
return events.map((eventName) => ({
event: eventName,
handler: (event) => onClickOutside({ event, el, handler, middleware })
}));
};
const directive = {
bind(el, { value }) {
const { handler, middleware } = processArgs(value);
const eventHandlers = eventAdapter(events, { el, handler, middleware });
instances.set(el, eventHandlers);
toggleEventListeners(eventHandlers)('add');
},
unbind(el) {
const eventHandlers = instances.get(el);
toggleEventListeners(eventHandlers)('remove');
instances.delete(el);
}
};
export default directive;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment