Vue基础——将原生事件绑定到组件
Vue基础——将原生事件绑定到组件
1、首先看一个小例子
父组件:
<template>
<div id="app">
<my-button @click="handleClick"></my-button>
</div>
</template>
<script>
import MyButton from "@/components/myButton";
export default {
name: 'App',
components: {MyButton},
methods: {
handleClick() {
console.log(111);
}
}
}
</script>
子组件
<template>
<div>点我</div>
</template>
<script>
export default {
name: "myButton",
data() {
return {}
},
computed: {},
methods: {},
mounted() {}
}
</script>
你觉得点击了按钮之后,会有输出吗?
鼠标按烂了都不会输出,不要按坏了你的鼠标🙅♀️(不过好像只有 Vue2 是如此,Vue3 会有输出)
我的理解是:HTML 自带的标签,是可以直接绑定原生事件的;但 Vue 里面提供的标签,是不行的,比如 组件标签、router-link 等,因为它没有该事件,所以它认为这是一个自定义事件
如果我非要绑定呢?
把父组件中改成:
<template>
<div id="app">
<my-button @click.native="handleClick"></my-button>
</div>
</template>
注意:给父组件绑定事件,原理是把该事件绑定到子组件的根标签。Vue 就是用这种手段去区分原生事件和组件自定义事件的,如果是原生,那么就给你绑定到该子组件的根标签;如果是组件自定义事件,那么就给你绑定到该组件标签上
2、以上通过加 .native 的方法,对点击事件挺好使,但是对 focus 事件不好使了。
举例如下:
父组件:
<template>
<div id="app">
<my-button @focus.native="handleClick"></my-button>
</div>
</template>
子组件:
<template>
<div>点我:<input type="text"></div>
</template>
翻译过来就是:我们给子组件的根标签绑定了一个聚焦事件,但是 div 标签本身就不具备 focus 事件,所以无论如何,它也聚不了焦,所以无论如何也无法触发
那么我们应该怎么触发呢?
让里面的 input 去触发,给 input 随便绑定一个原生事件,在事件回调函数里面写上 $emit 去触发(以下模板是组件自定义事件)
所以写法就是:
父组件:(千万注意:这里不要加上 .native 的后缀,因为加了,它就给你绑到子组件的根标签去了,而根标签是 HTML 自带的原生标签,你只能给它绑定原生事件)
<template>
<div id="app">
<my-button @focus="handleClick"></my-button>
</div>
</template>
子组件:
<template>
<div>点我:<input type="text" @focus="$emit('focus')"></div>
</template>
注意:
以下代码代表给该组件绑定一个名字叫做 click 的事件,这不叫 点击 事件,只是名字叫做 click,绑定到的是 my-button 标签上,而不是它的根标签,属于组件自定义事件的范畴(只能通过 $emit 触发)
<my-button @click="handleClick"></my-button>
这个代表给该组件的 子组件的根标签 绑定一个点击事件,因为根标签是原生标签,所以这是货真价实的点击事件。Vue 没有把它绑定到 my-button 上,而绑到了该子组件的根标签,属于原生事件的范畴
<my-button @click.navite="handleClick"></my-button>
3、进阶写法
父组件:
<template>
<div id="app">
<my-button @focus="handleClick"></my-button>
</div>
</template>
子组件:(基础写法)
<template>
<div>点我:<input type="text" @focus="sayHello"></div>
</template>
<script>
export default {
name: "myButton",
data() {
return {}
},
computed: {},
methods: {
sayHello() {
this.$emit('focus')
}
},
mounted() {}
}
</script>
子组件:(高级写法)
<template>
<!-- v-on 需要绑定的是一个属性,所以我们应该把它写在计算属性里面,并返回一个对象-->
<div>点我:<input type="text" v-on="sayHi"></div>
</template>
<script>
export default {
name: "myButton",
data() {
return {}
},
computed: {
// 原来计算属性的方法一开始就会执行
sayHi() {
// $listeners:只包含父组件上绑定的事件(不含 .native 修饰的),不包含自己的
let obj = Object.assign({}, this.$listeners, {
focus: () => {
console.log('input 框触发了 focus 事件');
this.$emit('focus')
}
})
console.log(obj);
return obj
}
},
methods: {},
mounted() {}
}
</script>
这里我们重写了 $listeners 身上的 focus 事件,然后干了一件什么事呢?(当 input 框触发了原生事件时,都会走下面这个对象里面的事件回调函数,这里其实是重写了 input 原生事件聚焦的回调函数)
this.$emit('focus')
,告诉父组件,我要你执行名字叫做 focus 的组件自定义事件的回调函数
这个方法就相当于是集成了所有事件,在处理多个事件时很方便
总结:
1、不能给自定义组件绑定原生事件,若要绑定原生事件,就要使用
.native
修饰符2、
<my-button @click="test" />
是绑定在了my-button
这个标签上而
<my-button @click.native="test" />
是绑定在了它里面的根标签上,即深入到组件内部去了