你可能有很屡次想要在一个组件的根元素上间接监听一个原生事件。这时,你能够应用 v-on 的 .native 修饰符:
<base-input v-on:focus.native="onFocus"></base-input>
在有的时候这是很有用的,不过在你尝试监听一个相似 <input> 的十分特定的元素时,这并不是个好主见。比方上述 <base-input> 组件可能做了如下重构,所以根元素实际上是一个 <label> 元素:
<label>
{{label}}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
这时,父级的 .native 监听器将静默失败。它不会产生任何报错,然而 onFocus 处理函数不会如你预期地被调用。
为了解决这个问题,Vue 提供了一个 $listeners property,它是一个对象,外面蕴含了作用在这个组件上的所有监听器。例如:
{focus: function (event) {/* ... */}
input: function (value) {/* ... */},
}
有了这个 $listeners property,你就能够配合 v-on=”$listeners” 将所有的事件监听器指向这个组件的某个特定的子元素。对于相似 <input> 的你心愿它也能够配合 v-model 工作的组件来说,为这些监听器创立一个相似下述 inputListeners 的计算属性通常是十分有用的:
Vue.component('base-input', {
inheritAttrs: false,
props: ['label', 'value'],
computed: {inputListeners: function () {
var vm = this
// `Object.assign` 将所有的对象合并为一个新对象
return Object.assign({},
// 咱们从父级增加所有的监听器
this.$listeners,
// 而后咱们增加自定义监听器,// 或覆写一些监听器的行为
{
// 这里确保组件配合 `v-model` 的工作
input: function (event) {vm.$emit('input', event.target.value)
}
}
)
}
},
template: `
<label>
{{label}}
<input
v-bind="$attrs"
v-bind:value="value"
v-on="inputListeners"
>
</label>
`
})
当初 <base-input> 组件是一个齐全通明的包裹器了,也就是说它能够齐全像一个一般的 <input> 元素一样应用了:所有跟它雷同的 attribute 和监听器都能够工作,不用再应用 .native 监听器。