使用自定义事件需要注意的细节

331 阅读2分钟

自定义事件详解

我们知道在父子通信中,父组件向子组件传递数据,我们可以使用props,那个么接下来我们来研究一下,子组件向父组件传递数据,我们使用自定义事件。

基本使用

遵循的规则:哪一个组件发射的事件,就在哪一个组件上绑定事件。

通过$emit()我们可以在子组件上发射一个事件,然后在父组件使用该子组件时,绑定相应的事件,这样就可以实现子组件向父组件传递数据了。

父组件:绑定事件有两种方式

  1. 通过【@事件名】来绑定事件

  2. 通过【$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();

补充:

  1. 如果指向触发一次,可以使用修饰符.on,或者$once()来只触发一次。
  2. 在组件绑定原生事件,需要使用.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简写。