父子组件通信
1. props
父组件给子组件添加属性 :fatherName="name" 传值,子组件通过props:['fatherName'] 接收;
子组件可以通过 this.$emit('changeFatherName','吴彦祖') 向父组件发送事件和数据,
父组件通过 @changeFatherName="changeFatherName" 监听事件和传递过来的数据
2. sync/update
v2.3新增语法糖,会扩展成一个更新父组件绑定值的 v-on侦听器;
<son :fatherName.sync="name" ref="son"></son>
子组件update:propName直接修改数据,父组件无需定义监听事件来接收数据
this.$emit('update:fatherName', '吴彦祖') 适合基本数据类型的传递和修改
3. provide/inject
父组件通过provide:{fatherAge:30}传值,子组件通过inject:["fatherAge"]接收,provide传递的数据,
不仅所有子组件都可以接收,所有后代组件均可以通过inject接收到
4. $attrs/$listeners
v2.4新增
$attrs 包含了父作用域中不作为 prop 被识别 (且获取) 的属性绑定 (class 和 style 除外)。
例如,父组件传递了 fatherName,fatherAge,fatherJob 三个属性 而子组件只通过props接收了fatherName 属性
子组件会默认渲染成<div fatherage="30" fatherjob="engineer"></div>, inheritAttrs:false 可以阻止这种默认行为,
子组件可以通过 v-bind="$attrs" 将这些属性传递给孙组件,相当于:fatherAge="$attrs.fatherAge" :fatherJob="$attrs.fatherJob"
$listeners 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器,它可以通过 v-on="$listeners" 传入内部组件
本例中子组件 可以用$listeners将父组件的changeFatherName事件监听传递给孙组件,使孙组件可以跨级修改父组件data
5. $children/$parent
父组件通过$children访问子组件属性和方法,子组件通过$parent访问父组件属性和方法,
this.$children[0].age=2 修改子组件数据,同理this.$parent.age=30 修改父组件数据
6. ref/refs
子组件绑定ref属性,父组件通过this.$refs['xxx']访问子组件,用法和 $children 相同;
本例中this.$refs['son']===this.$children[0] //true
//父组件
<template>
<div>
<h3>爸爸:</h3>
<div>姓名:{{ name }}</div>
<div>年龄:{{ age }}</div>
<button @click="seeSon">看看儿子</button>
<son
:fatherName="name"
:fatherAge="age"
:fatherJob="job"
@changeFatherName="changeFatherName"
ref="son"
></son>
<!-- <son :fatherName.sync="name" ref="son"></son> -->
</div>
</template>
<script>
import son from './son.vue'
export default {
components: {
son,
},
provide:{
fatherAge:30
},
data() {
return {
name:'father',
age:30,
job:'engineer'
}
},
methods:{
seeSon(){
// console.log(this.$refs['son']===this.$children[0]) //true
this.$children[0].age=2 //修改子组件数据
console.log(this.$children[0].age) //1 = 2
},
changeFatherName(val){
this.name=val
}
}
}
</script>
//子组件
<template>
<div>
<h3>{{ `儿子:我爸爸是${fatherName}; 今年${fatherAge}岁` }}</h3>
<div>姓名:{{ name }}</div>
<div>年龄:{{ age }}</div>
<button @click="seeFather">看看爸爸</button>
<button @click="changeFatherName">给爸爸改名字</button>
<grandson v-bind="$attrs" v-on="$listeners"></grandson>
</div>
</template>
<script>
import grandson from './grandson.vue'
export default {
components: {
grandson,
},
props: ['fatherName'],
inject: ['fatherAge'],
inheritAttrs:false,
data() {
return {
name:'baby',
age:1
}
},
methods:{
seeFather(){
console.log(this.$parent.age) //30
},
changeFatherName() {
this.$emit('changeFatherName','吴彦祖')
//this.$emit('update:fatherName', '吴彦祖')
}
},
created(){
console.log(this.$attrs) // { "fatherAge": "30", "fatherJob": "engineer" }
}
}
</script>
//孙组件
<template>
<div>
<h3>{{ `孙子:我爷爷今年${fatherAge}岁;是一个${fatherJob}; ` }}</h3>
<button @click="changeFatherName" >给爷爷改名字</button>
</div>
</template>
<script>
export default {
props: ['fatherJob'],
inject: ['fatherAge'],
inheritAttrs:false,
methods:{
changeFatherName () {
this.$emit('changeFatherName','孙子的爷爷')
},
},
created(){
console.log(this.$attrs) // { "fatherAge": "30" }
}
}
</script>
7. 子组件直接修改props/inject传过来的值
- 如果
props是基本数据类型,子组件中的prop会变化,父组件中不会变化且控制台会报错 - 如果
props是引用数据类型,父组件和子组件都会成功修改且不会报错(不建议这么做)
非父子组件、兄弟组件之间的数据传递
Vuex
详见官方文档vuex.vuejs.org/zh/ 后面补一篇Vuex原理,再详细整理😄
EventBus
eventBus 又称为事件总线,在vue中可以使用它来作为沟通桥梁的概念, 就像是所有组件共用相同的事件中心,
可以向该中心注册发送事件或接收事件, 所有组件都可以通知其他组件。
(维护困难,eventName起名字困难,不易维护,不及时注销事件会产生各种问题,复杂项目中还是使用Vuex)
//新建一个Vue实例作为中央事件总线
let EventBus = new Vue();
//监听事件
EventBus.$on('eventName', (val) => {
//......do something
});
//触发事件
EventBus.$emit('eventName', 'this is a message.');
//移除事件
EventBus.$off('eventName', {})
localStorage/sessionStorage
本地存储,某些业务中使用较多,比如记住用户tocken 系统设置等
window.localStorage.getItem(key) 获取数据,通过 window.localStorage.setItem(key,value) 存储数据;
注意:value只能值字符串类型,需要用JSON.parse() / JSON.stringify() 转换
sessionStorage同理
总结
-
父子组件通信:
props;.sync/update;provide/inject;$parent/$children;ref/refs;$attrs/$listeners -
非父子组件/兄弟组件通信: EventBus ; Vuex;localStorage/sessionStorage