vue2-父子组件通信与任意组件之间通信方式

86 阅读4分钟

前言

在实际的项目开发过程中,很多业务逻辑里面,vue组件之间需要相互传递数据,传递数据用的就是组件通信。而不同的组件之间也可进行数据交流和信息传递的过程。

1.父子组件通信

所谓父子组件通信其实就是,父组件向子组件传递数据 或者 子组件向父组件传递数据的过程。

1.1 父组件向子组件传递数据

父组件向子组件传递数据:通过props属性,在父组件中向子组件传递数据,子组件可通过props接收传递过来的数据。

语法

  1. 父组件使用v-bind绑定动态数据到子组件的标签上
<子组件标签 :属性名="动态数据"></子组件标签>
  1. 子组件通过props接收,接收的对象写法/类型校验/默认值
export default {
  props:{
     属性名: {
        type:'', //类型可以是number/object/boolean/array/data/function等...
        default:'' // 对象或者数组需要写函数
     }
    {
}
1.1.1 案例

假设有一个父组件parent和一个子组件Child,我们希望将message这个字符串传递给Child组件。

<template>
  <div>
    <Child :message="message" />
  </div>
</template>

<script>
import Child from './Child.vue';

export default {
  components: {
    Child //注册
  },
  data() {
    return {
      message: 'Hello from Parent'
    };
  }
}
</script>

在子组件Child中,我们可以通过props来接收来自父组件的数据。

<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  props: ['message']
}
</script>

在上述例子中,父组件使用了":message"的绑定机制,将父组件中的"message"属性值传递给了子组件的props。子组件则通过定义props来接收该属性值,并可以在模板中使用。

需要注意的是,props是单向数据流,只能由父组件向子组件传递数据,并且子组件不能修改props中接收到的数据。如果需要在子组件中修改父组件的数据,可以通过自定义事件或Vuex等其他方法来实现。

1.2 子组件向父组件传递数据

子组件向父组件传递数据:通过在子组件中触发自定义事件,父组件监听该事件,并在监听回调中接收数据。$emitVue实例的一个方法,它用于向父组件触发自定义事件并传递数据。通过在子组件中调用$emit方法,可以触发父组件中相应的事件处理函数,并将数据传递过去。

语法

  1. 子组件可通过this.$emit()把数据传递出去
this.$emit("自定义事件", 要传递出去的数据)
  1. 父组件通过在子组件标签上v-on绑定自定义事件接收数据
<子组件标签 @自定义事件="函数名"></子组件标签>
methods: {
  函数名(sonData){
    //sonData就是子组件传递过来的数据
  }
}
1.2.1 使用$emit方法的步骤
  1. 在父组件中定义一个事件处理函数,用来接收子组件触发的事件和传递过来的数据。
<template>
  <div>
    <!-- 监听子组件的自定义事件 -->
    <ChildComponent @custom-event="handleCustomEvent"></ChildComponent>
  </div>
</template>

<script>
  export default {
    methods: {
      // 定义事件处理函数
      handleCustomEvent(data) {
        // 处理接收到的数据
        console.log(data);
      }
    }
  }
</script>
  1. 在子组件中调用$emit方法来触发父组件的事件,并将需要传递的数据作为参数传递。
<template>
  <div>
    <button @click="triggerEvent">触发事件</button>
  </div>
</template>

<script>
  export default {
    methods: {
      // 触发事件
      triggerEvent() {
        // 使用$emit触发父组件的自定义事件,并传递数据
        this.$emit('custom-event', 'Hello from child component');
      }
    }
  }
</script>

在这个案例中,当子组件中的按钮被点击时,triggerEvent方法会调用$emit方法触发父组件的custom-event事件,并将字符串 'Hello from child component' 作为参数传递给父组件的事件处理函数 handleCustomEvent。这样父组件监听到子组件触发的事件后,就可以执行相应的逻辑来处理接收到的数据。

总结起来,$emit方法是Vue.js中一种简单而有效的组件通信方式,通过自定义事件和数据的传递,实现了子组件向父组件的通信。

1.2.2 v-on 指令

v-onVue.js 框架中非常重要的一个指令,用于监听DOM事件并执行相应的事件处理函数。通过v-on指令,你可以在模板中直接绑定事件监听器。

其次;v-on指令也可以用于父组件中监听子组件触发的事件。通过v-on指令,可以在父组件中指定一个事件处理函数,并对子组件发出的特定事件做出反应。

基本用法:

最基本的用法是将v-on指令绑定到一个事件名上,并在等号后面指定一个需要调用的方法名。

<button v-on:click="handleClick">Click me</button>
// 当按钮被点击时,handleClick 方法会被调用

缩写方法:

Vue.js 还提供了一种缩写语法,将v-on指令缩写为@符号。

<button @click="handleClick">Click me</button>
// @click 缩写方式达到了和之前基本用法相同的效果
// 即当按钮被点击时,执行 handleClick 方法

传递参数

有时候你可能需要在事件处理函数中传递额外的参数,可以通过$event参数获取事件对象

<button @click="handleClick('param')">Click me</button>
// 点击按钮时会调用 handleClick 方法,并传递 'param' 字符串作为参数

动态事件名

在一些特殊情况下,你可能需要动态地绑定不同的事件名。可以通过使用计算属性或者直接在表达式中调用方法来实现。

<template>
  <button v-bind:[Event]="handleEvent">Event</button>
</template>

<script>
  export default {
    data() {
      return {
        Event: 'click',
      };
    },
    methods: {
      handleEvent() {
        console.log('Dynamic event handled');
      },
    },
  };
</script>

在上面的示例中,Event 是一个动态属性,它的值会根据组件实例中的handleEvent方法动态变化,当点击按钮时,handleEvent方法会被调用。

修饰符

修饰符是附加到事件处理函数上的特殊后缀,用于修改事件的行为。Vue.js 提供了多种事件修饰符,例如 stoppreventcaptureselfenterspace 等,可以按需使用。

<button @click.stop="handleClick">Stop event propagation</button>

当然v-on的作用不止于此,除了这些之外还可以配合$emit作用于父子组件之间的通信。而在这里面v-on指令可以用于父组件中监听子组件触发的事件。通过v-on指令,可以在父组件中指定一个事件处理函数,并对子组件发出的特定事件做出反应。v-on指令需要指定监听的事件和相应的处理函数,以 v-on:事件名="回调函数" 的形式来使用。除了使用 v-on:事件名,还可以简写为 @事件名。前面已有它的用法。

且来看一个案例:首先是父组件的代码

<!-- 父组件 -->
<template>
  <div>
    <!-- 监听子组件的自定义事件 -->
    <ChildComponent @custom-event="handleCustomEvent"></ChildComponent>
  </div>
</template>

<script>
  export default {
    methods: {
      // 事件处理函数,接收子组件传递的数据
      handleCustomEvent(data) {
        console.log(data);
      }
    }
  }
</script>

子组件代码

<!-- 子组件 -->
<template>
  <div>
    <button @click="triggerEvent">触发事件</button>
  </div>
</template>

<script>
  export default {
    methods: {
      // 触发自定义事件,并传递数据给父组件
      triggerEvent() {
        this.$emit('custom-event', 'Hello from child component');
      }
    }
  }
</script>

在上面的示例中,当子组件中的按钮被点击时,triggerEvent方法会调用$emit方法触发父组件的custom-event事件,并将字符串 'Hello from child component' 作为参数传递给父组件的事件处理函数handleCustomEvent

父组件通过使用v-on指令监听子组件触发的custom-event事件,并指定相应的事件处理函数handleCustomEvent来处理接收到的数据。

1.2.3 使用$emit与v-on方法实现组件之间的通信时的注意事项
  1. 父组件需要在模板中通过v-on指令或者@符号来监听子组件触发的事件,并指定相应的事件处理函数。
  2. 事件名称要与子组件中使用$emit方法时的事件名称保持一致。
  3. 在父组件中定义的事件处理函数可以接收传递过来的数据,通常我们会将数据作为参数传递给事件处理函数

总结$emit方法用于子组件向父组件发送自定义事件,并将数据传递给父组件。v-on指令用于父组件监听子组件触发的事件,并执行相应的事件处理函数。这两种方法配合使用可以实现组件之间的双向通信。

2. 任意组件之间传递数据(跨级组件)

vue中,我们可以使用一个空的vue实例作为中央事件的总线(event bus)来实现任意组件之间数据的传递。步骤如下:

  1. 首先,我们需要在入口文件main.js中创建一个新的vue实例并且挂载到vue的原型上。以此作为事件的总线:
Vue.prototype.$bus = new Vue();
  1. 然后,在一个组件中,我们可以使用$bus.$emit触发一个事件,将数据传递出去:
this.$bus.$emit('自定义事件', 要传递出去的数据);
  1. 在另外一个组件中,通过vue的生命周期created中,通过$on监听自定义事件的方式,接收数据
created(){
this.$bus.$on(‘自定义事件’, function ( data ) { 
     // data就是从传递过来的数据
	})
}
2.1 示例代码

把数据传递出去的组件代码

// Son.vue
<template>
  <div class="son">
    子组件
    <br />
    <button @click="sendToOther">发送给其他儿子</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      msg2: "来自儿子的数据",
      msg: "任意组件间传递数据"
    };
  },
  methods: {
    sendToOther() {
      // 把数据传递出去
      this.$bus.$emit("atWill", this.msg);
    }
  }
};
</script>
<style lang="less" scoped>
.son {
  color: green;
  border: 1px solid green;
  height: 100px;
}
</style>

接收数据的组件代码

<template>
  <div class="other-son">
    其他儿子组件
    <br />
    自己的:{{ msg }}
    <br />
    别的组件传过来的: {{ otherMsg }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      msg: "其他儿子自己的数据",
      otherMsg: ""
    };
  },
  created() {
    // 接收数据
    this.$bus.$on("atWill", msg => {
      this.otherMsg = msg;
    });
  }
};
</script>

<style lang="less" scoped>
.other-son {
  margin-top: 20px;
  border: 1px solid orange;
  height: 150px;
}
</style>