首先介绍下父子组件生命周期执行顺序
加载渲染:
父beforeCreate —> 父created —> 父beforeMount —> 子beforeCreate —> 子created —> 子beforeMount —> 子mounted —> 父mounted
更新数据
父beforeUpdate —> 子beforeUpdate —> 子updated —> 父updated
销毁:
父beforeDestroy —> 子beforeDestroy —> 子destroyed —> 父destroyed
其次组件是 vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用。一般来说,组件可以有以下几种关系:
如上图所示,A 和 B、B 和 C、B 和 D 都是父子关系,C 和 D 是兄弟关系,A 和 C 是隔代关系,A 和 D 是隔代关系。
针对不同的使用场景,他们之间如何通信呢?
1.父子组件通信
父传子 v-bind 子接收父 props
子传父 $emit 父接收子 on
父调用子 $refs 子调用父 $parent
//父组件
<template>
<div>
<!-- 传递动态属性给子组件(title),短横线分割命名 -->
<header-child ref="child" :title="title" @getMessage="showMessage" :getList="getList"></header-child>
<button @click="getList">获取子组件的数据和方法1</button>
<button @click="showInfo(1,'男','小张')">获取子组件的数据和方法2</button>
</div>
</template>
<script>
import HeaderChild from "./HeaderChild.vue";
export default {
components: {
"header-child": HeaderChild,
},
data() {
return {
title: "我是父组件的数据",
message: "",
};
},
methods: {
getList() {
console.log(this.$refs.child.name);
},
run() {
console.log("我是父组件里面的方法");
},
showMessage(value) {
this.message = value;
console.log(this.message);
},
//通过ref调用子组件的方法传值
showInfo(id, type, name) {
this.$refs.child.getData(id, type, name);
},
},
};
//子组件
<template>
<div>
<button @click="getParent()">获取父组件的数据和方法</button>
<span>{{ getTitle }}</span>
</div>
</template>
<script>
export default {
//props是单向绑定的,即只能父组件向子组件传递
props: {
title:{
type:String,
default:""
},
//传递方法给父组件
getList: {
type: Function,
default: null,
},
},
data() {
return {
name: "我是子组件里面的数据",
};
},
methods: {
getParent() {
console.log(this.$parent.title);
this.$parent.run();
this.$emit("getMessage", "我通过emit方法传值给父组件");
this.getList()
},
getData(id, type, name) {
console.log(id, type, name);
this.id = id;
this.type = type;
this.name = name;
},
},
};
</script>
1.1 v-model如何实现父子组件之间通信?
<!--父组件-->
<template>
<div>
<child v-model="value"></child>
<span>{{ value }}</span>
</div>
</template>
<!--子组件-->
<template>
<div>
<input type="text" :myValue="value" @input="inputChange" />
</div>
</template>
<script>
//对于input事件, :myValue = 'value'也可以不写
export default {
data() {
return {};
},
props: ["value"],
model: {
prop: 'myValue',
event: 'input' //emit事件的名称,可以随便取,但下面emit事件的名字要对得上
},
methods: {
inputChange(e) {
//对于input事件,emit时的名称对应model中event的事件名
this.$emit("input", e.target.value);
},
},
};
</script>
它的原理是
1.展示:父组件中的v-model,子组件接收一个props值value,将它展示到子组件的input上。
2.改变:当子组件自身发生改变时,触发自身的input方法,然后触发父组件的事件方法,改变父组件的value,进而改变接收的props,实现自身展示的改变。
例子中使用了model,官网是这样说的,实际上是为了单选框,复选框按钮等情况的时候,他们的值并不是value,而是checked,这种情况下,就需要写这个。例如:
model: {
prop: 'checked',
event: 'change'
},
1.2 子组件如何修改父组件中的props?
对于传递过来的值是引用类型是可以直接修改的,但对于基本数据类型是不能修改的,此时如果想修改就需要使用sync,支持2.3版本级以上。
父组件引用
<icon-tab :activeIndex.sync="activeIndex"></icon-tab>
子组件修改
handleClick(index) {
this.$emit("update:activeIndex", index);
},
2.兄弟组件通信
2.1 Event Bus
//main.js
import Bus from './utils/bus'
Vue.prototype.$bus = Bus
//bus.js
import Vue from 'vue'
const Bus = new Vue()
export default Bus
使用时接收方和发送方的名字要一致
//发送方
this.$bus.$emit("showModal",data);
//接收方
created() {
this.$bus.$on("showModal",(value) => {
cosnole.log(value)
}
}
//销毁
beforeDestroy(){
this.$bus.off("showModal")
}
2.2 vuex
3.跨级组件通信
3.1 Event Bus
3.2 vuex
3.3 provide和inject
// 父级组件提供 'foo'
var Provider = {
provide: {
foo: 'bar'
},
}
// 子组件注入 'foo'
var Child = {
inject: ['foo'],
created () {
console.log(this.foo) // => "bar"
}
}