Как я могу зафиксировать событие клика по пользовательской директиве на Vue.js?
Я пытаюсь изучить Vue.js и пришел к практическому примеру, где мне нужно реализовать пользовательскую директиву, которая работает вши "v-on". Это означает, что мне нужно захватить событие click в моей пользовательской директиве и вызвать метод.
Шаблон, о котором я думал.
<template>
<h1 v-my-on:click="alertMe">Click</h1>
</template>
Проблема в том, что я не знаю, как зафиксировать событие click в пользовательской директиве. Извините неуклюжий код ниже.
<script>
export default {
methods: {
alertMe() {
alert('The Alert!');
}
},
directives: {
'my-on': {
bind(el, binding, vnode) {
console.log('bind');
el.addEventListener('click',()=>{
console.log('bind');
vnode.context.$emit('click');
});
},
}
}
}
</script>
Может кто-нибудь помочь мне понять, как это работает? Мне не удалось найти пример чего-то подобного.
6 ответов
После еще нескольких поисков я пришел к этому решению:
<template>
<h1 v-my-on:click="alertMe">Click me!</h1>
</template>
<script>
export default {
methods: {
alertMe() {
alert('The Alert!');
}
},
directives: {
'my-on': {
bind(el, binding) {
let type = binding.arg;
let myFunction = binding.value;
el.addEventListener(type, myFunction);
}
}
}
}
</script>
Решение, которое вы нашли, насколько я могу судить, является лучшим решением для того, что вы ищете. Однако для тех, кто мало что знает о Vue.JS, я подумал, что дам быстрое объяснение. Я также предлагаю вам ознакомиться с официальной документацией Vue для Custom Directives или моей статьей на Medium о концепциях.
Это код, к которому пришел Влад, и я бы поддержал его:
<template>
<h1 v-my-on:click="alertMe">Click me!</h1>
</template>
<script>
export default {
methods: {
alertMe() {
alert('The Alert!');
}
},
directives: {
'my-on': {
bind(el, binding) {
let type = binding.arg;
let myFunction = binding.value;
el.addEventListener(type, myFunction);
}
}
}
}
</script>
Короче говоря, директивы Vue вызываются в течение жизненного цикла элемента, к которому они прикреплены, на основе определения объекта директивы. В этом примере определенная функция называется "привязкой", поэтому директива будет вызывать эту функцию, когда элемент привязан к DOM.
Эта функция получает элемент, который она прикреплена к "el", и различное содержание использования директивы в "привязке" шаблона. При использовании привязки в шаблоне значение после двоеточия ":" - это "аргумент", который в этом примере является строковым литералом "щелчок". Значение внутри кавычек "" "- это" значение ", которое в данном случае является ссылкой на объект функции" alertMe".
Вары, которые определены путем получения binding.arg и binding.value (с их соответствующим содержимым), затем могут использоваться для создания прослушивателя событий, содержащегося внутри элемента "el", для которого используется директива (el можно изменять). Итак, когда элемент создается и привязан, этот новый прослушиватель событий создается для события "click", определенного аргументом "arg", и он вызывает функцию "alertMe", определенную значением "value".
Поскольку модификация содержится внутри элемента, вам не нужно беспокоиться об очистке при отмене привязки, потому что слушатель будет уничтожен, когда элемент будет уничтожен.
И это основное описание того, что происходит в предлагаемом коде. Чтобы узнать больше о директивах и о том, как их использовать, перейдите по предлагаемым ссылкам. Надеюсь, это поможет!
Вам необходимо зарегистрировать прослушиватель для события, генерируемого в вашей директиве.
// emit a custom event
// binding.expression is alertMe
vnode.context.$emit(binding.expression);
// listen for the event
export default {
created(){
this.$on('alertMe', event => {
this.alertMe()
})
},
....
}
Это не вызов метода alertMe
скорее мимоходом alertMe
до директивы в качестве выражения привязки:
<h1 v-my-on:click="alertMe">Click</h1>
У @Vlad есть отличное решение!
Могу я также добавить важный момент: если вы хотите передать параметры своему обратному вызову, это запутает вас тем, как Vue обрабатывает ваше выражение. Короче говоря, для пользовательских директив все, что находится между кавычками, оценивается и полученное значение передается (следовательно, вы можете получить его через binding.value (да!), А для встроенных директив, по крайней мере, для v-on, содержимое в кавычках оценивается позже, при срабатывании события.
Возможно, лучше всего это продемонстрировать, сравнив настраиваемую директиву и встроенную директиву v-on. Предположим, у вас есть директива my-on, написанная точно так же, как и @Vlad, и вы используете ее рядом с v-on:
встроенный:<h1 v-on:click="myAlert('haha')"> Click me!</h1>
Он работает как положено, при нажатии кнопки всплывает окно с предупреждением.
индивидуально:<h1 v-my-on:click="myAlert('haha')">Click me!</h1>
Как только отображается кнопка, всплывает окно предупреждения, и когда вы нажимаете на него, событие запускается, но ничего видимого не происходит. Это потому, что "myAlert('haha')" оценивается сразу после привязки (?), Следовательно, окно предупреждения, и его значение передается в вашу директиву (undefined или что-то еще), потому что его значение не является функцией, ничего не кажется произойдет. теперь обходной путь состоит в том, чтобы все, что находится между кавычками, возвращало функцию при оценке, например v-my-on:click="() => {myAlert('haha')}"
Надеюсь, это поможет.
Ссылки:
/questions/22880048/vue-v-on-schelchok-ne-rabotaet-na-komponente/55359986#55359986
Похоже, addEventListener работает только для нативных событий.
Чтобы поймать события, запущенные с помощью Vue, внутри директивы используйте $on
newdirective: {
bind(el, key, vnode){
vnode.componentInstance.$on('event-fired-from-component', someFunction)
},
....
}
Вы можете поместить этот код либо в свой компонент, либо в миксин в разделе директив, как этот
directives: {...}
А затем подключите его к компоненту, от которого вы хотите получить это событие.
<some-component
v-newdirective
></some-component>
Как сказал @Vlad, это сработало для меня:
el.addEventListener('click',()=>{
console.log('bind');
vnode.context.$emit('click');
Вот моя директива:
Vue.directive('showMenu', {
bind: function (el, binding, vnode) {
el.addEventListener('click', () => {
console.log('bind')
setTimeout(() => {
this.$emit('toggleDrawer')
}, 1000)
})
}
})
Спасибо приятель!