自定义事件详解
我们知道在父子通信中,父组件向子组件传递数据,我们可以使用props,那个么接下来我们来研究一下,子组件向父组件传递数据,我们使用自定义事件。
基本使用
遵循的规则:哪一个组件发射的事件,就在哪一个组件上绑定事件。
通过$emit()我们可以在子组件上发射一个事件,然后在父组件使用该子组件时,绑定相应的事件,这样就可以实现子组件向父组件传递数据了。
父组件:绑定事件有两种方式
-
通过【@事件名】来绑定事件
-
通过【$on】来绑定事件
需要注意的是,这种方式的回调函数,回调函数中的this是指向子组件的,如果想要让this指向父组件,我们可以使用箭头函数,或者将回调函数写到父组件的methods中。
this.$refs.son.$on("getName", function (name, age) { console.log(name, age); this.Name = name; //this指向子组件 console.log(this); });绑定方式:
//第一种
<template>
<div id="app">
//绑定子组件发射的事件
<son @getName="getname"></son>
</div>
</template>
//第二种
<script>
export default {
name: "App",
components: {
son,
},
methods: {
getname(name, age) {
console.log(name, age);
},
},
mounted() {
this.$refs.son.$on("getName", this.getname);
},
};
</script>
子组件:在发射事件时,可以在后面传递多个参数,但是我们推荐使用对象来传递多个参数。
<script>
export default {
name: "VueSon",
data() {
return {
name: "张三",
age: 19,
};
},
mounted() {},
methods: {
emitName() {
//使用对象传递多个参数
this.$emit("getName", { name: this.name, age: this.age });
//传递一个参数
this.$emit("getName", this.name);
},
eventoff() {
this.$off("getName");
},
},
};
</script>
解绑事件:
//解绑一个事件
this.$off('getName');
//解绑多个事件
this.$off(["getName", "getAge"]);
//清除该组件上所有的事件
this.$oof();
补充:
- 如果指向触发一次,可以使用修饰符.on,或者$once()来只触发一次。
- 在组件绑定原生事件,需要使用.native修饰符。
自定义输入组件
我们可以通过v-model来实现自定义输入组件。
父组件中 :
<comInput v-model="searchText"></comInput>
//使用v-model等价于下面绑定value和监听input事件
<mInput :value="searchText" @input="searchText = $event"></comInput>
子组件中:需要接受父组件传来的value值,然后动态绑定value,并且input事件发射自定义事件input,这样父组件在使用组件时就可以监听到。
<input
type="text"
:value="value"
@input="$emit('input', $event.target.value)"
/>
<script>
export default {
name: "VueCominput",
props: ["value"],
};
</script>
单选框或复选框等自定义组件
这种组件不同于输入组件,我们需要监听的不是value值,所以vue给我们提供了以model选项,可以设置监听的属性和事件。
以单选框为例:
<template>
<input
type="checkbox"
:checked="checked"
@change="$emit('change', $event.target.checked)"
/>
</template>
<script>
export default {
name: "VueCominput",
//阻止父组件的非props属性添加到组件的根元素上
inheritAttrs: false,
//设置监听的属性和方法
model: {
prop: "checked",
event: "change",
},
props: ["checked"],
};
</script>
<style lang="scss" scoped>
</style>
封装完全透明的输入组件
借助$listeners,我们不需要必须让input作为组件的根元素,我们可以通过该属性将所有的事件绑定到input上。实现完全透明的效果。
<template>
<label for="">
{{ label }}
<input type="text" v-on="$listeners" />
</label>
</template>
父子组件中值实现双向绑定
在很多情况下,我们希望子组件可以改变父组件传来的值,但是vue中不推荐我们直接改变props的值,所以我们就需要向父组件发射事件,让父组件来改变相应的值。
为了明确的知道是子组件想要改变父组件的值,vue给我们规定一种事件的写法:【update:myPropName】
例如:
//父组件中向子组件传递title属性
<comInput
:title="searchText"
@update:title="searchText = $event"
></comInput>
//子组件想改父组件传来的title值,我们可以这样写发射的事件名:updata:title
this.$emit("update:title", event.target.value);
为了方便,vue又为我们.sync修饰符,父组件可以之间简写为:
<comInput :title.sync="searchText"></comInput>
*注意:*只有我们使用【update:myPropName】这种写法书写事件名时,才可以使用.sync简写。