Vue 模板:如何自动将自定义属性添加到具有 v-on:click 指令的元素

Posted

技术标签:

【中文标题】Vue 模板:如何自动将自定义属性添加到具有 v-on:click 指令的元素【英文标题】:Vue template: How to automatically add custom attribute to elements that have a v-on:click directive 【发布时间】:2020-11-28 16:13:31 【问题描述】:

我们正在使用单个文件 vue 组件,并且在 mousemove 事件处理程序中,我们希望能够检测目标元素是否可点击。

在我们的 Vue 模板中,我们使用 v-on 指令:v-on:click="someCallback"

不幸的是,似乎没有一种简单的方法来判断给定元素是否注册了事件侦听器(即通过 v-on 指令)。

为此,我们希望使用 v-on:click 指令为这些元素添加自定义属性 - 即“可点击”。但这应该会自动发生。

所以我们必须要么将 Vue 自己的“on”指令包装到自定义指令中,要么以某种方式挂钩到 Vue 的渲染周期——但这似乎不是很直接:在 Vue 实例上找不到指令或Vue 组件对象。

我们尝试过的:

从传递给事件处理程序的事件对象提供的目标元素中检索有关已注册侦听器的信息。但显然浏览器不提供此信息。 在 Vue 组件对象中搜索某个对象,该对象存储有关哪个事件侦听器已为哪个元素注册到哪个处理程序的信息。我们无法找到此信息 - 但它应该在某个地方,对吧?

希望有人对如何使用 v-on:click 指令自动完成向元素添加自定义属性有一个很好的想法。

谢谢!

编辑: 所以我们有,即 <div id="x" @click="someMethod" /> 在我们的模板中。 但是我们想自动添加一个自定义属性(我们不想为所有万亿情况手动添加它): <div id="x" clickable @click="someMethod" /> 然后在 addEventListener('mousemove', handler) 的事件处理程序中,我们将检查这个属性:if (e.target.hasAttribute('clickable')) 但是任何其他实现这一点的方法(因此能够在 mousemove 的处理程序内部判断元素是否可点击)也可以。

【问题讨论】:

你能展示一个你想要实现的用例吗?因为它可能取决于您拥有什么、您正在使用的数据等。想想看,使用自定义 directiverefs 应该可以解决问题。但正如我提到的,请发布一些示例代码。 在底部添加了更多细节(编辑) 【参考方案1】:

您可以创建一个容器组件并将其导入所有其他 vue 组件,确保它是模板中的第一个组件,例如:

<template>
  <v-container>
    // your template here
  </v-container>
</template>

<script>
// Obviously replace the path and point to your location of the component
import ComponentContainer from './common/ComponentContainer.vue'
export default 
  name: 'MyClientComponent',
  components: 
    'v-container': ComponentContainer
  

</script>

这就是寻找点击事件并添加可点击类的容器组件:

<template>
  <div class="component-container">
    <slot></slot>
  </div>
</template>

<script>
export default 
  name: 'ComponentContainer',
  mounted() 
    this.$slots.default.forEach(vn => 
      this.addClickableClassNames(vn);
    );
  ,
  methods: 
    addClickableClassNames(vnode) 
      if (vnode) 
        let data = vnode.data;
        if (data && data.on) 
          // Check for click events and add a
          // clickable class if one exists
          if (data.on.click && vnode.elm && vnode.elm.classList) 
              vnode.elm.classList.add('clickable');
          
        
        // Now recursively check children
        if (vnode.children) 
          vnode.children.forEach(vn => 
            this.addClickableClassNames(vn);
          );
        
      
    
  

</script>

这可行,但我不想评论大型 dom 的性能。您和其他开发人员需要记住导入所有组件,这并不理想。但是,它是一个解决方案,可能会为您提供改进和提高可扩展性的其他想法。

【讨论】:

嗨,马克,感谢您的解决方案!不幸的是我们不能采用这种方法,数组 this.$slots.default 只包含父组件的包装元素。而且我们不能像那样改变我们的代码库。但无论如何这很有趣,因为我从来没有意识到 $slots.default 保存的是虚拟 DOM 的节点,而不是实际的 DOM :) 没有问题,不客气!希望你能解决你的问题。【参考方案2】:

我想不出“自动”添加这个可点击属性的方法。我认为不幸的是,您仍然需要一个一个地“标记”您的可点击元素。

我会有一个指令,您可以将它添加到模板中的任何元素中。

指令

Vue.directive('myDirective', 
  inserted(el, bindings) 
    el.addEventListener('mouseover', () => 
        alert(bindings.value);
    )
  
);

用法

<span v-my-directive="true">Element 1</span>
<span v-my-directive="false">Element 2</span>

您会注意到,在使用指令时,模板中会传递一个值。然后通过bindings.value 读取。当然,基于这个值你可以做任何你需要的功能。

JSFiddle:https://jsfiddle.net/tc45xf82/2/

Vue 文档:https://vuejs.org/v2/guide/custom-directive.html

【讨论】:

手动我也可以这样做:&lt;span clickable @click="..."&gt; ;)

以上是关于Vue 模板:如何自动将自定义属性添加到具有 v-on:click 指令的元素的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 API C# 和模板将自定义变量添加到 SendGrid 电子邮件

将自定义 css 添加到 wordpress 中的页面模板

如何将自定义页脚添加到 Bootstrap-Vue 表

如何将自定义属性添加到 Symfony Doctrine YAML 映射文件

将自定义属性添加到 asp.net-mvc 中的页面指令

将自定义 getter 添加到接收到的 json