Vue中几种常用的组件通信方式

在Vue项目开发中,会使用到很多组件,组件间的通信是Vue中的核心知识,掌握这几个知识,会让你Vue开发中游刃有余。

父子间通信

父传子
<!-- father.vue  -->
<div :fatherData = 'fatherData'></div>
//child.vue
//第一种
//props: ["fatherData"],
//第二种
 props: {
    fatherData: {
        type:String,
        default:'123'
    },
  },
子传父
<!-- father.vue  -->
<child @changeData="changeData"></child>
//child.vue
this.$emit("changeData", "需要传的参数");

祖孙间通信 provide / inject

允许一个祖先组件向其所有子孙后代注入一个依赖,可以注入属性和方法,从而实现跨级父子组件通信。

祖父传子孙
祖父 grandfather.vue
<template>
  <father></father>
</template>
<script>
import father from "./father.vue";
export default {
  data() {
    return {
      fruits: {
        apple: "苹果",
        banana: "香蕉",
        watermelon: "西瓜",
      },
    };
  },
  provide() {
    return {
      food: {
        fruits: this.fruits,
      },
    };
  },
  components: {
    father,
  },
};
</script>
父 father.vue
<template>
  <child></child>
</template>
<script>
import child from "./child.vue";
export default {
  components: {
    child,
  },
};
</script>
子 child.vue
<template></template>
<script>
export default {
  inject: ["food"],
  mounted() {
    console.log(this.food.fruits);
  },
};
</script>

看下打印结果:

image.png

子孙传祖父

祖父 grandfather.vue
<template>
  <father></father>
</template>
<script>
import father from "./father.vue";
export default {
  data() {
    return {
      fruits: {
        apple: "苹果",
        banana: "香蕉",
        watermelon: "西瓜",
      },
    };
  },
  provide() {
    return {
      food: {
        eat(value) {
          console.log(value);
        },
      },
    };
  },
  components: {
    father,
  },
};
</script>
子 child.vue
<template></template>
<script>
export default {
  inject: ["food"],
  mounted() {
    this.food.eat("爷爷吃水果!");
  },
};
</script>

看下打印结果:

image.png

兄弟间通信 EventBus

在main.js中初始化一个全局的事件总线。

Vue.prototype.$eventBus = new Vue()
父 father.vue
<template>
  <div>
    <childA></childA>
    <childB></childB>
  </div>
</template>
​
<script>
import childA from "./childA.vue";
import childB from "./childB.vue";
​
export default {
  components: {
    childA,
    childB,
  },
};
</script>
哥哥 childA.vue
<template></template>
​
<script>
export default {
  data() {
    return {
      num: 1,
    };
  },
  mounted() {
    //发布信息
    let timer = setInterval((res) => {
      this.$eventBus.$emit("give", this.num);
      this.num++;
    }, 300);
  },
};
</script>
弟弟 childB.vue
<template></template>
​
<script>
export default {
  mounted() {
    //订阅信息
    //接收哥哥给的水果
    this.$eventBus.$on("give", (value) => {
      console.log(`哥哥给了弟弟${value}苹果`);
      if (value >= 10) {
        //移除监听事件
        this.$eventBus.$off("give");
        console.log("弟弟不吃了");
      }
    });
  },
};
</script>

打印效果:

image.png

EventBus在小型项目中的确非常的好用,但是如果在大型项目用,大量的使用EventBus会导致项目难易维护。所以大型项目中建议使用Vuex

Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 解决了多个视图依赖于同一状态和来自不同视图的行为需要变更同一状态的问题。

  • State:用于数据的存储,是 store 中的唯一数据源;
  • Getter:类似于计算属性,就是对 State 中的数据进行二次的处理,比如筛选和对多个数据进行求值等;
  • Mutation:类似事件,是改变 Store 中数据的唯一途径,只能进行同步操作;
  • Action:类似 Mutation,通过提交 Mutation 来改变数据,而不直接操作 State,可以进行异步操作;
  • Module:当业务复杂的时候,可以把 store 分成多个模块,便于维护;
1.Vuex的安装
npm i vuex -s
2.将store挂载到当前项目的Vue实例当中去
//其他代码省略
import store from './store'
​
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')
3.初始化store目录下index.js中的内容
import Vue from 'vue'
import Vuex from 'vuex'
import fruits from './modules/fruits.js'
​
Vue.use(Vuex)
const store = new Vuex.Store({
  modules: {
    fruits
  }
})
​
export default store
4.在modules目录下fruits.js的内容
const fruits = {
    namespaced: true,  //开启namespace:true,该模块就成为命名空间模块了
    //仓库
    state: {
        apple: 10,
        banana: 10,
        watermelon: 10,
    },
    //mutation,通过提交来修改state仓库里面的数据
    mutations: {
        //加香蕉
        add(state) {
            state.banana++
        },
        //减苹果
        red(state) {
            state.apple--
        }
    },
}
export default fruits

页面

<template>
  <div>
    <div>苹果还有{{ apple }}个</div>
    <div>香蕉还有{{ banana }}根</div>
    <div>西瓜还有{{ watermelon }}个</div>
    <button @click="add">加香蕉</button>
    <button @click="red">减苹果</button>
  </div>
</template>
​
<script>
import { mapState, mapMutations } from "vuex";
export default {
  data() {
    return {
      apple: 0,
    };
  },
  mounted() {
    this.apple = this.$store.state.fruits.apple;
  },
  computed: {
    banana() {
      return this.$store.state.fruits.banana;
    },
    ...mapState({
      watermelon: (state) => state.fruits.watermelon,
    }),
  },
  methods: {
    //第一种写法
    // add() {
    //   this.$store.commit("fruits/add");
    // },
    //第二种写法
    // ...mapMutations({
    //   add: "fruits/add",
    // }),
    //第三种写法
    // ...mapMutations("fruits", {
    //   add: "add",
    // }),
    //第四种写法
    ...mapMutations("fruits", ["add"]),
​
    //苹果apple是data里面的属性,data属性只是在组件实例化时赋值一次,依赖发生变化时不会更新,所以减苹果页面不会及时响应变化
    //计算属性是基于它的依赖缓存的,计算属性在它的相关依赖发生改变时会重新取值,所以加香蕉页面会及时响应变化
    red() {
      this.$store.commit("fruits/red");
    },
  },
};
</script>

效果:

Vuex演示.gif

访问子组件实例或子元素

父 father.vue
<template>
  <div>
  <child ref="child"></child>
  </div>
</template>
​
<script>
import child from "./child.vue";
export default {
  components: {
    child,
  },
  methods: {
    getData() {
      this.$refs.child.getData();//getData为子组件里面的方法
    },
  },
};
</script>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值