无法在主机组件中的组件上获取DOM事件

时间:2019-05-27 02:17:14

标签: vue.js

我有一个Vue组件,其中包含一个名为lines的对象的列表。我根据行类型使用不同的组件从这些行构建表。这很完美。这是该组件的精简版本:

<template>
  <table>
    <tr v-for="line in lines"
        :key="line.key"
        :is="componentForType[line.eventType] || 'LogLine'"
        v-bind="line"
    />
  </table>
</template>

<script>
  export default {
    name: 'DebugLog',
    components: {
      LogLine,
      FormattedLogLine,
      UserDebug,
      Limits  
    },
    data () {
      return {
        lines: [],
        selectedKey: null,
        componentForType: {
          'USER_DEBUG' : 'UserDebug',
          'LIMIT_USAGE_FOR_NS' : 'Limits',
          'EXCEPTION_THROWN' : 'FormattedLogLine',
          'FATAL_ERROR' : 'FormattedLogLine'
        }

      }
    },
    mounted() {
      // code that loads this.lines
    }
  }
</script>

现在,我希望能够单击表的任何行,并使该行成为“选定的”,这意味着我要将line.key存储在this.selectedKey中,并使用CSS来以不同的方式呈现该行。但是我无法使事件正常进行。这是更新后的<template>;其他没有改变:

<template>
  <table>
    <tr v-for="line in lines"
        :key="line.key"
        :is="componentForType[line.eventType] || 'LogLine'"
        v-bind="line"
        :class="{selected: line.key == selectedKey}"
        @click.capture="selectedKey = line.key"
    />
  </table>
</template>

我在tr元素上添加了最后两个属性-动态类绑定和click事件处理程序,用于将this.selectedKey设置为活动行的键。但这不起作用。我用@click替换了console.log(line.key)处理程序代码,但未记录任何内容,这告诉我我的@click处理程序从未触发。我最初编写时没有使用.capture修饰符,但是在原始文档不起作用时尝试添加该修饰符。

vue.js是否停止从子组件传播到父组件?我不能将click事件绑定到tr上,因为它:is是另一个vue组件吗?还是还有其他事情发生?我在文档中找到的示例要简单得多,我不确定它们是否符合我的情况。各种子组件均未绑定任何点击事件。我宁愿如图所示完全在父事件中处理事件,因为我将有多种类型的子组件,并且我不想在每个子组件中都实现点击处理程序。

更新:在查看我的子组件时,我注意到每个子组件都包含一个tr标签,该标签必须有效替换父模板中的tr。例如,我最基本的组件是LogLine,如下所示:

<template>
  <tr>
    <td>{{timeStamp}}</td>
    <td>{{eventType}}</td>
    <td>{{lineNumber}}</td>
    <td>{{lineData}}</td>
  </tr>
</template>

<script>
  export default {
    name: 'LogLine',
    props: ['timeStamp', 'eventType', 'lineData', 'lineNumber'],
    data: function () {
      return {}
    }
  }
</script>

因此,我猜测父级中的绑定实际上未绑定到DOM中的tr上;它只是绑定在Vue组件上,侦听click从孩子发送来的$emit事件;并且每个子组件都需要在其@click上绑定tr并将其发送给父组件。假设我是对的,我可以使用父模板中的任何快捷方式来提示转发DOM事件吗?除了在每个子组件中绑定click之外,我还缺少其他任何选择吗?

3 个答案:

答案 0 :(得分:2)

由于您使用的是:is道具,因此它被视为动态Vue组件,而不是DOM元素。

默认情况下,不会将Vue组件上的事件侦听器传递到其DOM元素。您必须手动进入组件模板并添加v-on="$listeners"

演示:https://jsfiddle.net/jacobgoh101/am59ojwx/7/

例如<div v-on="$listeners"> ... </div>

答案 1 :(得分:2)

在这里背负雅各布的答案。由于本质上是将事件侦听器附加到动态组件,因此需要一个自定义click事件。因此,您在这里有两个选择:

1)侦听该组件中的本机DOM click事件(通过将click事件侦听器附加到组件中的常规DOM元素),并emit自定义{{1 }}事件发送给家长。

2)使用click修饰符to listen for the native DOM click event代替直接在父级中使用的自定义变量。

答案 2 :(得分:0)

@Jacob Goh对v-on="$listeners"的使用很简单,并且允许在一次操作中转发所有DOM事件,但是我想记录一下我为完整起见独自尝试的一种方法。 我将在我的组件中切换到Jacob的解决方案。我现在在父级中使用Husam的.native修饰符,因为它更适合我的特定用例。

我能够通过编辑每个子组件,捕获click事件并重新发送它来使我的组件正常工作。例如:

<template>
  <tr @click="$emit('click')">
    <td>{{timeStamp}}</td>
    <td>{{eventType}}</td>
    <td>{{lineNumber}}</td>
    <td>{{lineData}}</td>
  </tr>
</template>

<script>
  export default {
    name: 'LogLine',
    props: ['timeStamp', 'eventType', 'lineData', 'lineNumber'],
    data: function () {
      return {}
    }
  }
</script>