4

我正在尝试学习 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>

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

4

5 回答 5

14

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


<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>
于 2018-01-28T13:00:06.470 回答
3

据我所知,您找到的解决方案是您正在寻找的最佳解决方案。但是,对于那些对 Vue.JS 不太了解的人,我想我会给出一个快速的解释。我还建议您查看自定义指令的官方 Vue 文档或我关于这些概念的Medium 文章。

这是 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(及其各自的内容)定义的变量可用于创建包含在使用指令的元素“el”内的事件侦听器(el 是可修改的)。所以,当元素被创建和绑定时,这个新的事件监听器会在“arg”定义的“click”事件上创建,它会调用“value”定义的“alertMe”函数。

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

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

于 2020-02-07T13:50:00.673 回答
2

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

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

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

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

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

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

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

希望能帮助到你。

参考:

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

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

于 2020-06-13T05:53:59.337 回答
2

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

// 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>
于 2018-01-28T12:30:14.593 回答
0

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

多谢,伙计!

于 2019-02-14T13:47:51.650 回答