【问题标题】:How can I capture click event on custom directive on Vue.js?如何在 Vue.js 中捕获自定义指令的点击事件?
【发布时间】:2018-07-07 06:06:39
【问题描述】:

我正在尝试学习 Vue.js,并遇到了一个实践示例,我需要在其中实现一个自定义指令,该指令适用于 lice '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>

谁能帮我理解它是如何工作的?我没有找到任何类似的例子。

【问题讨论】:

标签: vue.js vuejs2 vue-directives


【解决方案1】:

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

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

【讨论】:

  • 我正在寻找一个指令,它可以监听像“点击”这样的事件,然后调用指定的方法,就像我在模板中提到的那样。
  • 这需要将isFn: true, // important! 添加到您的指令对象中。本页最后一节:optimizely.github.io/vuejs.org/guide/directives.html
  • 不需要isFn: true,看我的回答
【解决方案2】:

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


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

【讨论】:

  • 谢谢你,我对你的解决方案有补充,请看我的帖子
  • 如果不移除点击事件监听器会不会导致内存泄漏?
【解决方案3】:

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

谢谢老哥!

【讨论】:

    【解决方案4】:

    据我所知,您找到的解决方案是您正在寻找的最佳解决方案。但是,对于那些对 Vue.JS 不太了解的人,我想我会给出一个快速的解释。我还建议您查看 Custom Directives 或我的 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 指令在它们所附加的元素的生命周期中被调用,基于指令对象定义。在示例中,定义的函数称为“绑定”,因此指令将在元素绑定到 DOM 时调用该函数。

    此函数接收它附加到“el”的元素以及模板“绑定”中指令用法的不同内容。在模板的绑定用法中,冒号“:”后面的值是“arg”,在这个例子中是字符串文字“click”。引号 '""' 内的值是“值”,在这种情况下,它是对函数“alertMe”的对象引用。

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

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

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

    【讨论】:

      【解决方案5】:

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

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

      也许最好通过自定义指令和内置 v-on 指令之间的比较来证明这一点。假设你有一个与@Vlad 完全一样的“my-on”指令,并且你将它与 v-on 一起使用:

      内置: &lt;h1 v-on:click="myAlert('haha')"&gt; Click me!&lt;/h1&gt;

      它按预期工作,当单击按钮时,会弹出警报窗口。

      定制: &lt;h1 v-my-on:click="myAlert('haha')"&gt;Click me!&lt;/h1&gt;

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

      希望对你有帮助。

      参考资料:

      https://stackoverflow.com/a/61734142/1356473

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-04-22
        • 2018-05-08
        • 2019-01-05
        • 2020-10-05
        • 1970-01-01
        • 2013-03-14
        • 2021-03-13
        相关资源
        最近更新 更多