如何捕获 Vue.js 上自定义指令的点击事件?

How can I capture click event on custom directive on Vue.js?

我正在尝试学习 Vue.js 并来到了一个练习示例,我需要在其中实现一个自定义指令,它可以正常工作 'v-on'。 这意味着我需要在我的自定义指令上捕获点击事件并调用一个方法。

我想到的模板。

<template>
    <h1 v-my-on:click="alertMe">Click</h1>
</template>

问题是我不知道如何在自定义指令中捕获点击事件。请原谅下面笨拙的代码。

<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>

任何人都可以帮助我了解这是如何工作的吗?我没能找到任何类似的例子。

您需要为指令中发出的事件注册一个侦听器。

// 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>

经过更多搜索,我找到了这个解决方案:


<template>
  <h1 v-my-on:click="alertMe">Click me!</h1>
</template>

<script>

  export default {

    methods: {

      alertMe() {

        alert('The Alert!');

      }

    },

    directives: {

      'my-on': {

        // Add Event Listener on mounted.
        bind(el, binding) {
          el.addEventListener(binding.arg, binding.value);
        },

        // Remove Event Listener on destroy.
        unbind(el, binding) {
          el.removeEventListener(binding.arg, binding.value);
        }

      }

    }

  }
</script>

正如@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)
        })
    }
})

谢谢老兄!

据我所知,您找到的解决方案是您所寻找的最佳解决方案。然而,对于那些不太了解 Vue.JS 的人,我想我会给出一个快速的解释。我还建议您查看有关概念的 Custom Directives or my Medium article 的官方 Vue 文档。

这是 Vlad 得出的代码,我会支持:

<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 指令在它们附加到的元素的生命周期中被调用。在示例中,定义的函数称为 "bind",因此指令将在元素绑定到 DOM 时调用该函数。

此函数接收其附加到 "el" 的元素以及模板中指令用法的不同内容 "binding"。在模板中的绑定用法中,冒号“:”之后的值是 "arg",在本例中是字符串文字 "click"。引号 '""' 内的值是 "value",在本例中是对函数 "alertMe" 的对象引用。

然后可以使用通过获取 binding.arg 和 binding.value(及其各自的内容)定义的变量来创建包含在元素 "el" 中的事件侦听器指令用于(el 是可修改的)。因此,当元素被创建和绑定时,这个新的事件侦听器是在 "arg" 定义的 "click" 事件上创建的,它将调用 "value" 定义的 "alertMe" 函数。

因为修改是包含在元素内部的,所以不用担心unbind时的清理,因为元素销毁时监听器也会被销毁。

这是对建议代码中所发生情况的基本描述。要查看有关指令以及如何使用它们的更多信息,请点击建议的链接。希望对您有所帮助!

@Vlad 有一个很好的解决方案!

我还要补充一点:如果你想将参数传递给你的回调,Vue 处理你的表达式的方式会让你感到困惑。简而言之,对于自定义指令,引号之间的任何内容都会被计算并传入结果值(因此,您可以通过 binding.value 获取它(duh!),而对于内置指令,至少对于 v -on,当事件被触发时,引号之间的内容将在稍后计算。

也许这可以通过自定义指令和内置 v-on 指令之间的比较得到最好的证明。假设您有一个 "my-on" 指令完全按照@Vlad 的方式编写,并且您将它与 v-on:

并排使用

内置: <h1 v-on:click="myAlert('haha')"> Click me!</h1>

按预期工作,单击按钮时,弹出警报 window。

定制: <h1 v-my-on:click="myAlert('haha')">Click me!</h1>

一旦显示按钮,就会弹出警报 window,当您单击它时,会触发该事件,但不会发生任何可见的事情。这是因为 "myAlert('haha')" 在绑定 (?) 时立即被评估,因此警报 window,并且它的值被传递给您的指令(未定义或其他),因为它的值不是函数,没有似乎发生了。 现在,解决方法是在评估时将引号 returns 之间的任何内容作为函数,例如 v-my-on:click="() => {myAlert('haha')}"

希望对您有所帮助。

参考文献:

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