👌父组件想要在自定义组件的根元素上直接监听一个原生事件。这时,在 v-on 原生事件后使用 .native 修饰符是有用的
- 父组件:
<template>
<div id="app">
<BaseInput1 @focus.native="onFocus" v-model="value"/>
</div>
</template>
<script>
import BaseInput1 from './components/BaseInput1.vue'
export default {
name: 'App',
data(){
return {
value: ''
},
components: {
BaseInput1
},
methods:{
onFocus(){
alert('onFocus')
}
}
}
</script>
- 子组件
<template>
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</template>
<script>
export default {
name:"",
inheritAttrs: false,
props: {
value: String,
}
}
</script>
<style lang="less">
</style>
<label> 元素
<label>
{{label}}
<input
v-bind="$attrs"
v-bind:value="value"
v-on="inputListeners"
>
</label>
| 前父子组件关系 | 后父子组件关系 |
|---|---|
app >> BaseInput1 (input为根元素) |
app >> BaseInput1 (label为根元素) >> input |
🤔解决方案:让 BaseInput1 组件变成一个完全透明的包裹器,也就是让它可以完全像一个普通的 <input> 元素一样使用:让所有跟它相同的 attribute 和监听器都可以工作。
如果你对inheritAttrs&&$attrs&&$listeners不熟悉,推荐你看下面这篇推文🙌:
inheritAttrs&&$attrs&&$listeners 【Vue 2.4.0新增inheritAttrs,attrs详解】
- 父组件:
<template>
<div id="app">
<!-- 它可以完全像一个普通的 <input> 元素一样使用,无需再使用.native修饰符了 -->
<BaseInput1 label="将原生事件绑定到组件" @focus="onFocus" v-model="value"/>
<h2>{{value}}</h2>
</div>
</template>
<script>
import BaseInput1 from './components/BaseInput1.vue'
export default {
name: 'App',
data(){
return {
value: ''
}
},
components: {
BaseInput1
},
methods:{
onFocus(){
alert('onFocus')
}
}
}
</script>
- 子组件:
<template>
<label>
{{label}}
<input
v-bind="$attrs"
v-bind:value="value"
v-on="inputListeners"
>
<!--使用 v-on="$listeners" 将所有的事件监听器指向这个组件的某个特定的子元素。
对于类似 <input> 的你希望它也可以配合 v-model 工作的组件来说
可以为这些监听器创建一个类似inputListeners 的计算属性-->
</label>
</template>
<script>
export default {
name:"",
inheritAttrs: false,
props: {
value: String,
label: String,
},
computed: {
inputListeners: function(){
var vm = this
// `Object.assign` 将所有的对象合并为一个新对象
return Object.assign({},
// 我们从父级添加所有的监听器
this.$listeners,
// 然后我们添加自定义监听器,
// 或覆写一些监听器的行为
{
// 这里确保组件配合 `v-model` 的工作
input: function(event){
vm.$emit('input',event.target.value)
}
}
)
}
}
}
</script>
<style lang="less">
</style>