Background
I created a custom directive (to detect clicks outside of an element) by following this guide: https://tahazsh.com/detect-outside-click-in-vue.
Element:
<button
id='burger'
ref='burger'
class='burger button is-white'>
<span class='burger-top' aria-hidden='true' style='pointer-events: none;'></span>
<span class='burger-bottom' aria-hidden='true' style='pointer-events: none;'></span>
</button>
Directive:
import Vue from 'vue';
let handleOutsideClick;
Vue.directive('outside', {
bind(el, binding, vnode) {
setTimeout(() => {
handleOutsideClick = (e) => {
e.stopPropagation();
const { handler, exclude } = binding.value;
let clickedOnExcludedEl = false;
exclude.forEach((refName) => {
if (!clickedOnExcludedEl) {
const excludedEl = vnode.context.$refs[refName]
console.log(vnode.context.$refs);
clickedOnExcludedEl = excludedEl.contains(e.target);
}
});
if (!el.contains(e.target) && !clickedOnExcludedEl) {
vnode.context[handler]();
}
};
document.addEventListener('click', handleOutsideClick);
document.addEventListener('touchstart', handleOutsideClick);
}, 50);
},
unbind() {
document.removeEventListener('click', handleOutsideClick);
document.removeEventListener('touchstart', handleOutsideClick);
},
});
Note that I have had to add setTimeout
.
Using the directive in a sidebar component:
<div
id='sidebar'
class='sidebar-container'
v-show='toggleSideBar'
v-outside='{
handler: "close",
exclude: [
"burger",
],
}'>
<div class='sidebar-content'>
// other content
</div>
</div>
Problem
$refs
is empty, even though the element clearly has a ref
.
This is clear also from console.log(vnode.context.$refs);
.
Notably, getting the element by id works:
exclude.forEach((id) => {
if (!clickedOnExcludedEl) {
const excludedEl = document.getElementById(id);
clickedOnExcludedEl = excludedEl.contains(e.target);
}
});
Question
Why is $refs
empty when the element clearly exists and can be accessed by id?