vue中组件通信的方式

Posted 别Null.了

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue中组件通信的方式相关的知识,希望对你有一定的参考价值。

目录

props

$emit

ref和$ref实现父子组件之间的通信

全局事件总线bus

创建一个事件总线bus

组件间传值(这里用于兄弟组件传值)

依赖注入(provide/inject)

$parent/$children

vuex通信

插槽slot

匿名插槽(默认插槽)

具名插槽

作用域插槽


props

props只能用于父组件向子组件传递数据,子组件通过props获得父组件传递过来的数据,子组件的数据会随着父组件的更新而响应式更新。

<!-- 父组件 -->
<template>
  <div class="father">
    <span>我是父组件</span>
    <Children :msg="name"></Children>
  </div>
</template>
<script>
import Children from "./Children.vue";
export default 
  components: 
    Children,
  ,
  data() 
    return 
      name: "张三",
    ;
  ,
;
</script>
<!-- 子组件 -->
<template>
  <div class="child">我是子组件,父组件传递过来的数据是: msg </div>
</template>
<script>
export default 
  props: 
    msg: String,
  ,
  data() 
    return ;
  ,
;
</script>

实现结果为:   

$emit

适用任意组件通信,通常用于子组件向父组件传递数据。$emit 绑定一个自定义事件,当这个事件被执行的时候就会将参数传递给父组件,而父组件通过v-on监听并接收参数(v-on可以缩写成@)。

<!-- 父组件 -->
<template>
  <div class="father">
    <Children :list="list" @onEmitIndex="onEmitIndex"></Children>
    <p>子组件传递过来的index数据为: index </p>
  </div>
</template>

<script>
import Children from "./Children.vue";
export default 
  components: 
    Children,
  ,
  data() 
    return 
      index: -1,
      list: ["第一", "第二", "第三"],
    ;
  ,
  methods: 
    onEmitIndex(id) 
      this.index = id;
    ,
  ,
;
</script>
<!-- 子组件 -->
<template>
  <div>
    <div v-for="(item, index) in list" :key="index" @click="emitIndex(index)">
       item 
    </div>
  </div>
</template>

<script>
export default 
  props: ["list"], //子组件先获取父组件chuan'gu
  data() 
    return ;
  ,
  methods: 
    emitIndex(index) 
      this.$emit("onEmitIndex", index); //触发父组件方法onEmitIndex,传递参数index
    ,
  ,
;
</script>

实现结果: 

ref和$ref实现父子组件之间的通信

在父组件中使用ref注册要引用的子组件信息,再使用$ref获取所有注册的引用信息。

<!-- 父组件 -->
<template>
  <Children ref="child"></Children>
</template>
<script>
import Children from "./Children.vue";
export default 
  components:  Children ,
  mounted() 
    console.log(this.$refs.child.name);  //获取子组件中的数据name
    this.$refs.child.sayHello(); //获取子组件中的方法
  ,
;
</script>
<!-- 子组件 -->
<template>
  <div></div>
</template>

<script>
export default 
  data() 
    return 
      name: "javascript",
    ;
  ,
  methods: 
    sayHello() 
      console.log("hello");
    ,
  ,
;
</script>

全局事件总线bus

适用于任意组件之间的通信,在vue中类似桥梁,是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所有组件都可以通知其他组件。使用$emit发布事件,$on订阅事件。

在用这个传值方法时有一个问题,尤其是在父子组件之间用的时候,从一个组件中使用$emit触发事件之后,另一个组件的监听事件$on不生效,所以在使用bus传值时,$on一定要在$emit事件触发之前创建,否则在触发$emit事件时,$on是监听不到的(因为这个时候$on压根就没有创建) 。

创建一个事件总线bus

import Vue from "vue";
export default new Vue();

组件间传值(这里用于兄弟组件传值)

<!-- 父组件 -->
<template>
  <div>
    <Children1></Children1>
    <Children2></Children2>
  </div>
</template>
<script>
import Children1 from "./Children1.vue";
import Children2 from "./Children2.vue";
export default 
  components:  Children1, Children2 ,
;
</script>
<!-- 子组件1:发送事件 -->
<template>
  <div>
    <button @click="add">将子组件1中的num发送给子组件2</button>
  </div>
</template>

<script>
import bus from "../bus/bus.js"; //引入事件总线
export default 
  data() 
    return 
      num: 0,
    ;
  ,
  methods: 
    add() 
      bus.$emit("addition", 
        num: this.num++,
      );
    ,
  ,
;
</script>
<!-- 子组件2:接收事件 -->
<template>
  <div>求和: count </div>
</template>

<script>
import bus from "../bus/bus.js"; //引入事件总线
export default 
  data() 
    return 
      count: 0,
    ;
  ,
  mounted() 
    bus.$on("addition", (param) => 
      this.count = this.count + param.num;
    );
  ,
;
</script>

实现结果:

依赖注入(provide/inject)

用于父子、祖孙组件之间的通信,适用于层数很深情况下的传值。provide和inject是vue的两个钩子,provide用来发送事件,inject用来接收事件。

假设A组件中引入B组件(A为B的父组件),B组件中引入C组件(B为C的父组件,A为C的爷爷组件),则A,C通过provide/inject通信。

<!-- A组件:使用provide -->
<template>
  <div>
    <C></C>
  </div>
</template>
<script>
import C from "./C.vue";
export default 
  components:  C ,
  provide() 
    return 
      name: "哈利波特",
    ;
  ,
;
</script>
<!-- C组件:使用inject -->
<template>
  <div> name </div>
</template>

<script>
export default 
  inject: ["name"],
;
</script>

输出为: 

$parent/$children

使用$parent可以访问上一级父组件;使用$children可以访问子组件,获得的是数组,不能保证所访问的子组件顺序,数据不是响应式。

<!-- 父组件 -->
<template>
  <div class="hello_world">
    <div>Father组件中的值为: msg </div>
    <Children></Children>
    <button @click="change">点击改变子组件值</button>
  </div>
</template>

<script>
import Children from "./Children.vue";
export default 
  components:  Children ,
  data() 
    return 
      msg: "Welcome",
    ;
  ,
  methods: 
    change() 
      this.$children[0].message = "JavaScript"; //获取到第一层子组件
    ,
  ,
;
</script>
<!-- 子组件 -->
<template>
  <div>
    <span>Children组件值为(点击后改变): message </span>
    <p>获取父组件的msg为:  parentVal </p>
  </div>
</template>

<script>
export default 
  data() 
    return 
      message: "Vue",
    ;
  ,
  computed: 
    parentVal() 
      return this.$parent.msg;
    ,
  ,
;
</script>

实现结果: 

vuex通信

适用任意组件间的通信,主要实现多个组件共享数据,是进行数据状态管理的一个插件。

创建文件:src/store/index.js(创建vue项目时选择vuex会自动生成并配置此文件)

如果创建时未选择可以使用它进行安装:npm install --save vuex@3.6.2

src/store/index.js的文件内容为:

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);  //安装插件
export default new Vuex.Store(
  state: , //定义全局共享的数据
  getters: , //vuex的计算属性,所有组件共享,访问方式:this.$store.getters.函数名
  mutations: , //用于修改state数据(同步函数),使用方式如:state.count++
  actions: , //用来接收异步请求数据,接收到数据后要把数据先拿到mutations,用mutations把数据存入state,访问方式:this.$store.dispatch(“函数名”,参数)  函数名为actions中定义的函数名
  modules: ,
);

在main.js中挂载使用:

插槽slot

匿名插槽(默认插槽)

不需要设置name属性,默认为default。

<!-- 父组件 -->
<template>
  <div class="father">
    <h1>我是父组件</h1>
    <Children>
      <!-- 如果children里没有定义slot的话,Children里的内容不会显示 -->
      <p>我是默认的插槽</p>
    </Children>
  </div>
</template>
<script>
import Children from "./Children.vue";
export default 
  components:  Children ,
;
</script>
<!-- 子组件-->
<template>
  <div>
    <h2>我是子组件</h2>
    <slot></slot>
  </div>
</template>
<script>
export default ;
</script>

slot所实现的地方:

实现结果:  

具名插槽

slot是带有name的,要用一个template标签包裹,多个具名插槽中所实现插槽的位置是按照在定义的时候的位置来替换的。Vue3中将v-slot简写为:#

<!-- 父组件 -->
<template>
  <div class="father">
    <h1>我是父组件</h1>
    <Children>
      <!-- 如果children里没有定义slot的话,Children里的内容不会显示 -->
      <p>我是默认的插槽</p>
    </Children>
  </div>
</template>
<script>
import Children from "./Children.vue";
export default 
  components:  Children ,
;
</script>
<!-- 子组件-->
<template>
  <div>
    <h2>我是子组件</h2>
    <slot name="peopleName"></slot>
  </div>
</template>
<script>
export default ;
</script>

实现结果:    

作用域插槽

用来传递数据的插槽,v-solt可以解构接收,解构接收的字段要和传的字段一样,例如 :one 对应 v-slot="one"

<!-- 父组件-->
<template>
  <div class="father">
    <h1>我是父组件</h1>
    <Children>
      <template v-slot=" one ">
        <p>我是匿名插槽: one.name </p>
      </template>
      <template v-slot:footer="slotProps">
        <p>我是底部具名插槽: slotProps.users.name </p>
      </template>
    </Children>
  </div>
</template>
<script>
import Children from "./Children.vue";
export default 
  components:  Children ,
;
</script>
<!-- 子组件-->
<template>
  <div>
    <h2>我是子组件</h2>
    <slot :one="user1"></slot>
    <slot name="footer" v-bind:users="user"></slot>
  </div>
</template>

<script>
export default 
  data() 
    return 
      user1: 
        name: "哈利波特",
      ,
      user: 
        name: "赫敏",
      ,
    ;
  ,
;
</script>

实现结果: 

以上是关于vue中组件通信的方式的主要内容,如果未能解决你的问题,请参考以下文章

vue 提供注入 provideinject 深层嵌套通信

Vue-Cli—04.父子组件传值祖孙组件传值兄弟组件传值

vue组件化编程父子组件通信

vue组件化编程父子组件通信

vue实现组件通信的5中方式

vue组件通信的几种方式