43
loading...
This website collects cookies to deliver better user experience
HTMLElement
.bind:this
approach to getting a local reference to a DOM element, but there's a better way. The use:
directive allows for reusable logic to be pulled out of the component itself.Modal
component I created a clickOutside
action that can be reused elsewhere. This can also help make testing a whole lot easier, testing the async nature of a full blown Modal component can be tricky, testing just the action itself is much less complicated!onMount
or onDestroy
, but actions are tied to DOM elements themselves rather than entire Svelte components.bind:this
when the component you're working on needs to interact with a DOM element. I won't jump into the DRY design principles debate, instead just look at the testing challenges.action = (node: HTMLElement, parameters: any) => {
update?: (parameters: any) => void,
destroy?: () => void
}
action
function can run initialization logic on the element before returning update
and destroy
handlers (both optional).export default (node, _options = {}) => {
const options = { onClickOutside: () => {}, ..._options };
function detect({ target }) {
if (!node.contains(target)) {
options.onClickOutside();
}
}
document.addEventListener("click", detect, { passive: true, capture: true });
return {
destroy() {
document.removeEventListener("click", detect);
},
};
};
_options
). The action expects options.onClickOutside
to be a callback function, if one wasn't provided it's defaulted to a noop function.detect
function does the real work of checking to see if a click event on the page was inside the original DOM element. The event listener is using passive
to avoid scrolling performance issues, and capture
to make sure that all clicks bubble up to the listener.destroy
callback that will clean up the event listener when the element is being removed from the DOM.export default (node, _options = {}) => {
const options = { include: [], onClickOutside: () => {}, ..._options };
function detect({ target }) {
if (
!node.contains(target) ||
options.include.some((i) => target.isSameNode(i))
) {
options.onClickOutside();
}
}
/** Same as above */
};
click
event so the test can count how many times the onClickOutside
handler was called!43