vue中组件通信的方式

本文详细介绍了Vue中各种组件通信的方式,包括props、$emit、ref和$refs、全局事件总线bus、依赖注入provide/inject、$parent/$children以及vuex状态管理。通过实例展示了如何在不同组件间传递数据,实现复杂应用的数据共享和通信。
摘要由CSDN通过智能技术生成

目录

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>

实现结果: 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

别Null.了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值