在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>
看下打印结果:
子孙传祖父
祖父 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>
看下打印结果:
兄弟间通信 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>
打印效果:
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>
效果:
访问子组件实例或子元素
父 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>