目录
遇到问题首先要查官方文档
https://v2.cn.vuejs.org/v2/guide/components-edge-cases.html
文档能首先解决60% - 80%的问题。
0.了解子组件与父组件的关系
- 加载渲染过程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
- 子组件更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
- 父组件更新过程
父beforeUpdate->父updated
- 销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
导入子组件
1.父组件调用子组件内容【一对一】
首先这个一对一表示的是一个父组件下同名的只有一个子组件。【即子组件不可以被v-for包围】
1.1 父组件调用子组件的methods
-
指定名称,ref是组件标签自带的一个属性,直接写就好了,表示被引用【reference】时的名称。
-
在js栏中调用子组件的方法,$refs是Vue对象的一个实例属性,存储当前vue对象中所引用的组件标签。我们刚刚指定了子组件的名称,直接对应然后就可以调用该名称组件内部的方法了。
无论是方法1还是放发2,多关注是否使用了v-if在子组件上,v-if为false的时候,未渲染组件,无法通信。
方法2:
方案二:通过组件的$emit、$on方法;
复制代码
//父组件中
<template>
<div>
<Button @click="handleClick">点击调用子组件方法</Button>
<Child ref="child"/>
</div>
</template>
<script>
import Child from './child';
export default {
methods: {
handleClick() {
this.$refs.child.$emit("childmethod") //子组件$on中的名字
},
},
}
</script>
//子组件中
<template>
<div>我是子组件</div>
</template>
<script>
export default {
mounted() {
this.$nextTick(function() {
this.$on('childmethods', function() {
console.log('我是子组件方法');
});
});
},
};
</script>
以上两种方法都是基于this.$refs调用子组件,要求子组件已渲染,如果子组件使用了v-else等导致无法立即渲染的,可能会失效。【输出this.$refs可以看到有哪些子组件】,建议换用v-show。
2.子组件调用父组件内容【一对一】
一个子组件只有一个父组件
2.1 子组件调用父组件的methods
子组件直接使用this.$parent.xxx()即可,注意方法名是其父组件要已经定义的。
(效果有点不好)
在一对一的父子通信下,该方法更加简单。当然有另一种方法是使用$emit,下面的多对一中会讲到。
2.2 子组件调用父组件的属性
-
指定名称,即指定ref
-
先进入子组件,子组件中指定需要的变量的名称,指定字符串名称即可,因为只作为该组件的属性名!同时要注意,props是一个数组,而且是官方指定的vue实例的一个属性,所以其级别是和methods和data是同级的,不要放到里面去了。而且这个是在子组件中定义!
-
这里的item和i都是for内的临时值,没有在父类的return中定义。如果绑定this.父类的属性。则要求props中提供的变量名不能与之重复。比如父类return {num: 10}; 子类中不允许props: {‘num’}; 要改为props: {‘myNum’}
-
在进入父组件,对于子组件需要访问的变量,我们直接双向绑定,属性名与子组件的props数组中定义的一致,而绑定的对象就是父组件的属性变量,可以是如图的v-for的对象,也可以是data中的变量对象。【如果出错了,检查自己是不是加了this.属性,一律不要加this.属性, 直接输入变量名就好了】
如图:【先别看@loadComments,下面会介绍】
- 进入子组件,直接使用变量item
这里的值是可以直接在method中使用的,在method中监察可以使用watch。而如果需要修改父组件的值,最好在父组件添加一个方法,使用method调用在父组件中进行修改
注意:
vue 中父组件向子组件传递数据用 props, 但是子组件是无法修改它的。如果子组件需要动态修改它就只能自造一个对应的 data 域。比如
components:{Tinymce},
props:['id','formDatas'],
data() {
return {
form: {
title: '',
title_type: '',
push_date: '',
source: '',
title_introduce: '',
title_content:'',
}
}
},
created(){
this.form = this.formDatas
},
这样是无法把props的值传递给data里面,因为data()只会运行一次,所以要用watch来进行监听props里面内容的变化,然后对data里面进行赋值
【是news而不是new】
watch:{
formDatas(news,olds){
this.form = news
}
}
因此当父组件传递值给子组件的时候,watch就会监听到formDatas的变化,将新的值赋给你想要传值的data,然后进行改变。
3.父组件调用子组件【一对多】
一个父组件下有多个同名子组件。如图,通过v-for后,名为Comments的组件在当前父组件中可就不止一个了。
3.1 父组件调用子组件的methods
-
如果我们仍然使用
this.$ref.xxx
肯定无法获取,因为有多个同名组件。 -
那很容易理解,这多个同名对象一定被撞到一个容器中了。即
this.$ref.xxx[i]
不就行了!?如图官方文档
- 从理论上确实可以,但是实际上,我尝试这样去获取的时候,发现这个容器【应该是个set】中的元素是无序的,我每次获取Comment[0],得到的vue对象都时不一样的。如图:
- 所以如果是在v-for下的情况,是不可以使用
this.$ref.xxx[i]
来获取子组件对象的 - 并且官方文档也警示我们,不要在v-for的场景下使用$refs获取子组件。
- 解释一下官方文档。v-for和v-if一样,指令都是响应了数据变化再渲染的。而如果对数据的修改不是响应式的,那么v-for和v-if就不会自动重新渲染,即使数据变更了。比如你发表了一个帖子,如果对数据进行非响应式修改,那么页面不会出现新帖子的数据。
- 所以$refs访问子组件是一种非响应式访问,应该避免在需要响应式的场景中使用。
- 因此!在响应式场景【v-for、v-if】目前不建议父组件去调用子组件的方法,本来就可以单独交给子组件做的就在子组件中完成。
- 也不建议使用
this.$ref.xxx[i]
,因为对于索引来说会失控
解决方向参考:
- 最优的解决方向是,对于子组件自己完成该功能所需要的参数,由父组件提供【即指定props数组】即可,由子组件自己完成自己的方法。父组件尽量不要去调用子组件的方法。
- 比如说把触发响应时间的DOM从父组件剥离去到子组件,避免父组件响应然后去调用子组件。
4.子组件调用父组件【多对一】
即多个同名子组件对应一个父组件。
4.1 子组件调用父组件的属性
与**子组件调用父组件的属性【一对一】**一致,使用props数组
4.2 子组件调用父组件的methods
- 同子组件要访问属性一样,变量数据是双向绑定,那调用方法就是一个事件
- 但是要注意,目前对于子组件的事件,不需要像props数组一样提前定义
- 首先我们进入父组件,对子组件对象添加一个触发事件,事件名称与要调用的父组件方法同名即可,如图的loadComments
- 然后我们进入子组件,再需要使用父组件方法的地方使用 e m i t 属性,其语法规则为 ‘ t h i s . emit属性,其语法规则为`this. emit属性,其语法规则为‘this.emit(事件名,参数1,参数2,…)`,只需要第一个参数是事件名即可,其余的参数个数不定,根据父组件方法的参数个数进行传参。
补充:bus的使用
官方对于兄弟组件进行通信,使用的是$bus
总结【一般使用】
-
父调用子
- 父组件调用子组件的属性:一般不会调用
- 父组件调用子组件的方法:使用$refs.子组件的ref名.方法名调用
-
子调用父
- 子组件调用父组件属性:先在子组件中定义props数组指明数据名,然后在父组件中对子组件标签进行双向绑定。
- 子组件调用父组件方法:
- 子组件直接使用this.$parent.方法名调用
- 父组件中对子组件标签进行事件绑定父组件的方法,然后子组件中使用$emit()方法触发事件
-
如果父子通信出现在v-for的场景下
- 父组件无法调用子组件的方法,因为$refs的索引不可控
- 子组件调用父组件方法不可以使用非响应式的this. p a r e n t . 方法名,而需要使用 parent.方法名,而需要使用 parent.方法名,而需要使用emit
- 子组件调用父组件的属性的方式不变