将原生事件绑定到自定义组件
原生事件在自定义组件上是不起作用的
<template>
<div>
<my-component @click="outClick"></my-component>
</div>
</template>
<script>
import Vue from 'vue';
Vue.component('my-component',{
template:'<button>点击我</button>'
})
export default {
methods:{
outClick(){
alert(111112)
}
}
}
</script>
//此时点击按钮无任何反应
添加修饰符.native,原生事件在自定义组件上就起作用了
<template>
<div>
<my-component @click.native="outClick"></my-component>
</div>
</template>
<script>
import Vue from 'vue';
Vue.component('my-component',{
template:'<button>点击我</button>'
})
export default {
methods:{
outClick(){
alert(111112)
}
}
}
</script>
//此时点击会弹框
可以理解为该修饰符的作用就是把一个vue组件转化为一个普通的HTML标签,并且该修饰符对普通HTML标签是没有任何作用的
<template>
<div>
<my-component @click.native="outClick"></my-component>
<div @click.native="outClick">ddddd</div>
//在div标签上用.native修饰符没有任何作用,不会弹框
</div>
</template>
<script>
</script>
如果子组件的根元素是一个label标签或者是div一类的标签,那么.native将会失效
<template>
<div>
<my-component @focus.native="outClick"></my-component>
</div>
</template>
<script>
import Vue from 'vue';
Vue.component('my-component',{
template:'<label><input placeholder="获取焦点" /></label>'
})
export default {
methods:{
outClick(){
console.log(111113)
}
}
}
</script>
为了解决这个问题,Vue 提供了一个 $listeners 属性,它是一个对象,里面包含了作用在这个组件上的所有监听器。例如:
{
focus: function (event) { /* ... */ }
input: function (value) { /* ... */ },
}
有了这个 $listeners
属性,你就可以配合 v-on="$listeners"
将所有的事件监听器指向这个组件的某个特定的子元素。
注意:使用.native修饰符的事件,不会体现在$listeners属性上。
<template>
<div>
<my-component @focus="outClick"></my-component>
//这里不要用.native
</div>
</template>
<script>
import Vue from 'vue';
Vue.component('my-component',{
template:'<label><input v-on="$listeners" placeholder="获取焦点" /></label>'
//用v-on="$listeners"将所有的事件监听器指向input上
})
export default {
methods:{
outClick(){
console.log(111113)
}
}
}
</script>
$listeners 和 v-model 配合,需要计算属性inputListeners,把父组件传递进来的事件和v-model用到的事件合并为一个新对象
<template>
<div>
<base-input v-model="username" label="基础输入组件" @click.native="fnClick" @focus="fnFocus" placeholder="请输入" />
</div>
</template>
<script>
import Vue from 'vue';
// 注册组件
// 因为base-input的外层是一个label元素,所以默认情况下使用v-on:focus是无效的,所以需要配合$listeners使用,该属性可以把事件的监听指向组件中某个特定的元素
// 注意:如果父级的事件添加了.native修饰符,在$listeners中不会体现出来的
Vue.component('base-input',{
inheritAttrs: false,
props: ['label','value'],
template: `
<label>
{{label}}
<input v-bind="$attrs" v-on="inputListeners"/>
</label>
`,
data() {
return {
}
},
computed: {
inputListeners () {
var vm = this
return Object.assign({}, // `Object.assign` 将所有的对象合并为一个新对象
this.$listeners,
{
input: function () {
vm.$emit('input', event.target.value) //默认的event为input
},
focus: function (event) {
vm.$emit('focus', '哈哈哈,onfocus了') //第二个参数是fnFocus的参数
},
aa:function(){
vm.$emit('focus', '哈哈哈,onfocus了')
} //增加的事件
}
)
}
},
mounted: function(){
console.log(`$attrs:`)
console.log(this.$attrs)
console.log(`$listeners:`)
console.log(this.$listeners) // 父级添加的所有属性都在这里
console.log(this.inputListeners)
},
methods: {
}
})
export default {
data(){
return {
username: ''
}
},
beforeUpdate: function () {
console.log(this.username)
},
methods: {
fnFocus: function(ev){
console.log(`111111111111${JSON.stringify(ev)}`)
},
fnClick: function(ev){
console.log(ev.type)
}
}
}
</script>
网友评论