- 使用 v-on 的 .native 修饰符:
<base-input v-on:focus.native="onFocus"></base-input>
在有的时候这是很有用的,不过在你尝试监听一个类似 的非常特定的元素时,这并不是个好主意。比如上述 组件可能做了如下重构,所以根元素实际上是一个
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
这时,父级的 .native 监听器将静默失败。它不会产生任何报错,但是 onFocus 处理函数不会如你预期地被调用。
**原因:父级元素 的根元素是,元素监听了focus事件,但实际上,事件的触发源是 元素。并且
- 元素没有focus事件
- 即使有focus事件,当前template中元素只默认监听了input事件。事件向上传递后,也无法触发根元素事件 **
- 使用Vue 提供的一个 $listeners 属性
Vue 提供了一个 $listeners 属性,它是一个对象,里面包含了作用在这个组件上的所有监听器。例如:
{
focus: function (event) { /* ... */ }
input: function (value) { /* ... */ },
}
对于类似 的你希望它也可以配合 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 v-on:listener-name="methodName"></base-input>
说明: 上面的代码中, this. l i s t e n e r s 其 实 是 获 取 了 < b a s e − i n p u t > 这 个 父 级 组 件 中 定 义 的 所 有 的 监 控 事 件 l i s t e n e r − n a m e , 再 加 上 i n p u t 事 件 , 就 能 使 得 < b a s e − i n p u t > 组 件 像 一 个 普 通 的 < i n p u t > 元 素 一 样 使 用 了 。 ∗ ∗ 特 别 说 明 : ∗ ∗ 如 果 在 < b a s e − i n p u t > 通 过 v − o n 或 v − m o d e l 的 方 式 , 监 听 i n p u t 事 件 , 那 么 t h i s . listeners其实是获取了<base-input>这个父级组件中定义的所有的监控事件listener-name,再加上input事件,就能使得<base-input> 组件像一个普通的 <input> 元素一样使用了。 **特别说明:**如果在<base-input> 通过v-on或v-model的方式,监听input事件,那么this. listeners其实是获取了<base−input>这个父级组件中定义的所有的监控事件listener−name,再加上input事件,就能使得<base−input>组件像一个普通的<input>元素一样使用了。∗∗特别说明:∗∗如果在<base−input>通过v−on或v−model的方式,监听input事件,那么this.listeners就会取到这个input监听事件,但在Object.assign()时,同名的监听事件,后者会覆盖前者。因此即使在父级组件中定义input监听,也不会出现问题。
另外
<base-input v-on:listener-name="methodName"></base-input>
对组件的子组件建立监控的时候,其实更像是在的实例中定义了一个listener-name为名称的函数,然后通过$emit反射调用。