Вызов bind
для функции создает новую функцию. Слушатели не удаляются, потому что функция, которую вы передаете removeEventListener
, - это не та функция, которую вы передали addEventListener
.
. Связь между перехватчиками в директивах не особенно проста. Официальная документация рекомендует использовать элемент dataset
, хотя в этом случае это выглядит неуклюже:
https://vuejs.org/v2/guide/custom-directive.html#Directive -Hook-Arguments
Вы можете просто сохранить слушатели для элемента непосредственно в качестве свойств, чтобы они были доступны в хуке unbind
.
Код ниже использует несколько иной подход. Он использует массив для хранения всех элементов, которые в настоящее время связаны с директивой. Слушатель на window
регистрируется только один раз, независимо от того, сколько раз используется директива. Если директива в настоящее время не используется, этот слушатель удаляется:
let foxElements = []
function onClick () {
console.log('click triggered')
for (const entry of foxElements) {
clickHandler(entry.el, entry.arg)
}
}
function clickHandler (el, arg) {
console.log('clicked', el, arg)
}
new Vue({
el: '#app',
data () {
return {
items: [0]
}
},
directives: {
fox: {
inserted (el, binding) {
console.log('inserted')
if (foxElements.length === 0) {
console.log('adding window listener')
window.addEventListener('click', onClick)
}
foxElements.push({
el,
arg: binding.arg
})
},
unbind (el, binding) {
console.log('unbind')
foxElements = foxElements.filter(element => element.el !== el)
if (foxElements.length === 0) {
console.log('removing window listener')
window.removeEventListener('click', onClick)
}
}
}
}
})
<script src="https://unpkg.com/vue@2.6.11/dist/vue.js"></script>
<div id="app">
<button @click="items.push(Math.floor(Math.random() * 1000))">Add</button>
<hr>
<button
v-for="(item, index) in items"
v-fox:example
@click="items.splice(index, 1)"
>Remove {{ item }}</button>
</div>
Однако все это предполагает, что директива является даже верным путем к go. Если вы можете просто сделать это на уровне компонентов, то это может стать намного проще, потому что у вас есть экземпляр компонента, доступный для хранения вещей. Просто помните, что вызов bind
создает новую функцию, поэтому вам нужно где-то хранить ссылку на эту функцию, чтобы вы могли передать ее в removeEventListener
.