vue父子组件通讯的几种方式总结学习
一直都是公司前端在写组件,我想着自己也写一波,然后先看看父子组件传值的内容,想写一写小demo然后练习一下这个内容,也算是系统学习一下怎么处理这个内容
其实就是2种父传子和子传父
1.父组件传子组件数据
其实就是父在标签中可以给子传值主要利用props
子组件
<template>
<h3>Child
<div>{{ name }}</div>
<div>{{ age }}</div>
</h3>
</template>
<script>
export default{
name:"childCompont",
props:{
name:{
type:String,
default:"",
require:true
},
age:{
type:Number,
default:1
}
},
data(){
return{
}
},
}
</script>
父组件
<template>
<div>
<h3>{{ message }}</h3>
<child-compont :name=name :age=age />
</div>
</template>
<script>
import childCompont from './childCompont.vue'; //1、导入Child组件
export default {
name: 'parentCompont',
components: { childCompont }, //2、注入Child组件
data() {
return {
name:"娃哈哈",
age:"1",
message: "Parent"
}
},
}
</script>
父组件可以1.动态传值,2.直接传字符串
子组件可以1.设置默认值,2.必传校验,3.然后设置默认值,类型校验
亲自试了了一下,如果校验不通过确实会报红
这个小学习其实就是通过props属性将父组件的值传递给子组件,任何类型的值都可以作为props的值被传递,另外需要注意的是props传递数据,只能从父级传递到子级,不能反其道而行。只能接收
props对数据类型的校验,用type规定父组件传过来的数据类型,如果不相符,控制台会抛出警告;默认值,default,数字和数组可以直接default:数据类型,而数组和对象,必须通过工厂函数返回默认值;必选项,通过required:true,要求父组件传值过来,否则控制台会抛出警告,最后要注意的是props接收的值是只读的,不能进行修改操作。
2.利用事件子组件传父组件数据
实际应用的场景,比如说我封装了一个下拉组件,然后下拉 然后再一个组件中使用这个下拉组件,然后我点击了这个下拉组件后,需要把下拉中的相关信息复写到父组件中,其实就是需要用这个内容,简单的说就是想把子组件的内容暴露给父的时候需要这个样子去处理。
可以在子组件中通过$emit(event, […参数])触发一个自定义的事件,这样,父组件可以在使用子组件的地方直接用 v-on来监听子组件触发的事件, 并且可以在监听函数中依次取得所有从子组件传来的参数,但是这个前提是说,在子组件有东西可以传递这个时间的情况下,可以这么去做。
例如:
在子组件中某个部分写入:
this.emit('aaa', arg);
然后你就可以在父组件的子组件模板里监听:
// 这里是父组件的Template:
<child @ aaa= "functionYours" />
子组件
<template>
<h3>Child
<button @click="click1">按钮给父传值1</button>
<button @click="click2">按钮给父传值2</button>
</h3>
</template>
<script>
export default{
name:"childCompont",
props:{
},
data(){
return{
}
},
methods: {
click1(){
console.log("按钮1答应打印1")
this.$emit("slectChange","按钮1点击了第一个参数","按钮1点击了第二个参数")
},
click2(){
console.log("slectChange","按钮2点击了")
this.$emit("slectChange","按钮2点击了")
}
},
}
</script>
父组件
<template>
<div>
<h3>{{ data }}</h3>
<h3>{{ data2 }}</h3>
<child-compont @slectChange = "change"/>
</div>
</template>
<script>
import childCompont from './childCompont.vue'; //1、导入Child组件
export default {
name: 'parentCompont2',
components: { childCompont }, //2、注入Child组件
data() {
return {
data:"默认值",
data2:"默认值2",
}
},
methods: {
change(data,data2){
this.data = data
this.data2 = data2
}
},
}
</script>
3通过ref属性在父组件中直接取得子组件的数据修改(data)
上面说的有个局限性就是它们都需要以事件机制为基础(无论是像click那样的原生事件还是自定义事件),而在事件发生的时候才能调用函数将数据传递过来,就是肯定要有事件产生才能传值,
但如果子组件里没有类似“按钮”的东西,因而无法制造原生事件,同时也没办法找到一个触发自定义事件的时机的时候,怎么从子组件向父组件传递数据呢?
这个时候, 我们就只能从父组件中“直接取”子组件的数据了,借助ref属性
ref是我们经常用到的Vue属性,利用它可以简单方便地从本组件的template中取得DOM实例,而实际上,如果你在父组件中为子组件设置ref的话, 就可以直接通过vm.$refs.[子组件的ref].[子组件的属性]去拿到数据啦,例如:
实际的场景使用:就是你想从父直接修改或者触发子组件的方法的时候,可以使用这个内容,和上面时间不同的是,就是上面那个需要有事件才行,但是ref没这个限制,直接就可以从父访子。
handleAdd() {
this.$refs.addEdit.type = "add";
this.$refs.addEdit.beforeLoadForm();
this.$refs.addEdit.visible = true;
},
4通过sync实现数据双向绑定, 从而同步父子组件数据
通过以上三种方式, 我想你应该能解决绝大多数父子组件通信的场景了,但让我们再仔细考虑一下上面的通信场景,就会发现它们还可能存在的问题:
从子组件向父组件传递数据时,父子组件中的数据仍不是每时每刻都同步的
但在某些特殊的需求场景下,我们可能会希望父子组件中的数据时刻保持同步, 这时候你可能会像下面这样做:
这是父组件中的template:
<son :foo="bar" v-on:update="val => bar = val"></son>
在子组件中, 我们通过props声明的方式接收foo并使用
props: {
foo: [type]
}
同时每当子组件中数据改变的时候,通过
this.$emit('update', newValue)
把参数newValue传递给父组件template中监听函数中的"val"。然后通过
val => bar = val
这个表达式就实现了bar = newValue. 这个时候,我们发现父组件这个表达式就实现了bar = newValue. 这个时候,我们发现父组件中的关键数据bar被子组件改变(相等)了!
通过数据的双向绑定, 父(组件)可以修改子的数据, 子也可以修改父的数据
Vue提供了sync修饰符简化上面的代码,例如:
<comp :foo.sync="bar"></comp>
会被扩展为:
<comp :foo="bar" @update:foo="val => bar = val"></comp>
然后你需要在子组件中改变父组件数据的时候, 需要触发以下的自定义事件:
this.$emit("update:foo", newValue)
【注意】你可能觉得这好像和我上面提到的二中的“通过自定义事件(emit)从子组件向父组件中传递数据”的那一节的内容似乎重叠了,。然而并不是, 两者有着父子组件关系上的不同,
1.在我们讲解sync的这一小节里, 自定义事件发生时候运行的响应表达式是:
<son :foo="bar" v-on:update="val => bar = val"></son> 中的 "val => bar = val"
2.在二中的“通过自定义事件从子组件向父组件中传递数据” 里,自定义事件发生时候运行的响应表达式是:
<Son v-on: eventYouDefined = "arg => functionYours(arg)" /> 中的 "arg => functionYours(arg)"
对前者, 表达式 val => bar = val意味着强制让父组件的数据等于子组件传递过来的数据, 这个时候,我们发现父子组件的地位是平等的。 父可以改变子(数据), 子也可以改变父(数据),2者的关系完全不像是父和子的关系,更像是朋友,这种的。就是父组件中的数据变化可以后可以影响子组件,然后子改变了以后也可以改变父组件
对后者, 你的functionYours是在父组件中定义的, 在这个函数里, 你可以对从子组件接受来的arg数据做任意的操作或处理, 决定权完全落在父组件中, 也就是: 父可以改变子(数据), 但子不能直接改变父(数据)(就是说你需要触发父组件的时间来改变父的内容)!
数据双向绑定是把双刃剑
从好处上看:
1.它实现了父子组件数据的“实时”同步, 在某些数据场景下可能会使用到这一点,
4.sync提供的语法糖使得双向绑定的代码变得很简单
从坏处上看:
它破环了单向数据流的简洁性, 这增加了分析数据时的难度