Как я могу зафиксировать событие клика по пользовательской директиве на 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

https://github.com/vuejs/vue/issues/5588

Похоже, 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)
        })
    }
})

Спасибо приятель!

Другие вопросы по тегам