文章目录
- 前言
- 一、父子组件通信
- 1、父传子
- ①使用`props`接收父组件传递的属性
- ② 使用`$attrs`接收父组件未在 `props` 和 `emits` 中定义的属性和事件
- ③使用 `$parent`获取父组件的信息
- 2、子传父
- ① 使用 `$emit`传递信息给父组件
- ② 使用`$refs`获取子组件的属性和事件
- 二、自定义事件:适用于兄弟组件或“距离”较远的组件
- 三、多级组件上下级:`provide`、`inject`
- 总结
前言
组件通信在工作中很常见,但通讯的方式很多且使用场景也不同,故在此记录和总结。
一、父子组件通信
1、父传子
①使用props
接收父组件传递的属性
// 父组件
<template>
<Helloword :msg=msg />
</template>
<script>
export default {
data() {
return {
msg: 'message'
}
}
}
</script>
// 子组件
<template>
<h1>{{ msg }}</h1>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
},
}
</script>
② 使用$attrs
接收父组件未在 props
和 emits
中定义的属性和事件
- 父组件level1,向level2传递属性a、b、c和事件getA()、getB()、getC()
// level1.vue
<template>
<p>Level1</p>
<Level2
:a="a"
:b="b"
:c="c"
@getA="getA"
@getB="getB"
@getC="getC"
></Level2>
</template>
<script>
import Level2 from './Level2'
export default {
name: 'Level1',
components: { Level2 },
data() {
return {
a: 'aaa',
b: 'bbb',
c: 'ccc'
}
},
methods: {
getA() {
return this.a
},
getB() {
return this.b
},
getC() {
return this.c
}
}
}
</script>
- 组件level2使用
this.$attrs
,接收父组件未在props
和emits
中定义的属性和事件
// level2.vue
<template>
<p>Level2</p>
<Level3
:x="x"
:y="y"
:z="z"
@getX="getX"
@getY="getY"
@getZ="getZ"
v-bind="$attrs"
></Level3>
</template>
<script>
import Level3 from './Level3'
export default {
name: 'Level2',
components: { Level3 },
props: ['a'],
emits: ['getA'],
data() {
return {
x: 'xxx',
...
}
},
methods: {
getX() {
return this.x
}
...
},
created() {
console.log('level2', Object.keys(this.$attrs)) // 是 props 和 emits 后补
},
}
</script>
- 子组件level3接收父组件level2中,未被
props
和emits
接收的属性和事件。level2组件中定义level3组件时,使用v-bind="$attrs"
可接收level1中未在props
和emits
中定义的属性和事件。
<template>
<p>Level3</p>
</template>
<script>
export default {
name: 'Level3',
props: ['x'],
emits: ['getX'],
inheritAttrs: false, // 避免在dom节点中,增加传递的属性,如:<p b='b' c='c'></p>。使用attrs,在只有一个根元素时,就会生成
created() {
console.log('level3', Object.keys(this.$attrs)) // 是 props 和 emits 候补
}
}
</script>
$attrs
可以实现多级组件传递,但是依赖v-bind="$attrs"
。它是 props 和 emits 候补
③使用 $parent
获取父组件的信息
mounted() {
console.log(this.$parent.getX())
},
2、子传父
① 使用 $emit
传递信息给父组件
父组件
<template>
<HelloWorld :getMsg="getMsg"/>
</template>
<script>
export default {
name: 'HelloWorld',
methods: {
getMsg(msg) {
console.log(msg);
}
},
}
子组件
// 子组件:HelloWorld
<template>
<button @click = "clickHandler">传递</button>
</template>
<script>
export default {
name: 'HelloWorld',
// emits: ['showMsg'], // Vue3
methods: {
clickHandler() {
this.$emit('getMsg', 'hello world')
}
},
}
</script>
② 使用$refs
获取子组件的属性和事件
父组件
<template>
<p>Level3</p>
<HelloWorld msg="hello 双越" ref="hello1"/> // 子组件
</template>
<script>
import HelloWorld from '../HelloWorld'
export default {
...
mounted() {
console.log(this.$refs.hello1.name) // created里面组件未渲染完成,需要再mounted里面获取
},
}
</script>
二、自定义事件:适用于兄弟组件或“距离”较远的组件
兄弟组件1
<template>
<p><button @click="trigger">点击传值</button></p>
</template>
<script>
import event from '../utils/event.js'
export default {
name: 'CustomEvent2',
methods: {
trigger() {
event.emit('showMsg', 'hello custom event') // 触发事件
}
},
}
</script>
// 兄弟组件2
<template>
<p>接收值</p>
</template>
<script>
import event from '../utils/event.js'
export default {
name: 'CustomEvent1',
methods: {
showMsg(msg) {
console.log(msg)
}
},
mounted() {
event.on('showMsg', this.showMsg) //绑定事件
},
// Vue2.x beforeDestroy
beforeUnmount() {
event.off('showMsg', this.showMsg) // 组件销毁需要off事件。否则会造成内存泄漏
},
}
</script>
Vue 版本的区别
- Vue 2.x 可以使用 Vue 实例作为自定义事件
- Vue 3.x 需要使用第三方的自定义事件,例如 https://www.npmjs.com/package/event-emitter
自定义事件可能出现多个触发多个绑定,所以,容易造成项目混乱,用的时候要遵守规范。
三、多级组件上下级:provide
、inject
传递数据的组件,使用provide
传递
<template>
<p>Level1: <input v-model="name"></p>
<Level2></Level2>
</template>
<script>
import { computed } from 'vue'
import Level2 from './Level2'
export default {
name: 'Level1',
components: { Level2 },
data() {
return {
name: 'lisa'
}
},
provide() {
return {
info: computed(() => this.name) // cmputed包裹响应式数据,实现下级组件数据响应式
}
}
}
</script>
需要被传递数据的组件使用inject
接收。支持多层或多个组件接收。
<template>
<p>Level2 {{info}}</p>
<Level3></Level3>
</template>
<script>
import Level3 from './Level3'
export default {
name: 'Level2',
components: { Level3 },
inject: ['info']
}
</script>
总结
- 父子组件通讯
props
emits
this.$emit
$attrs
(也可以通过v-bind="$attrs"
向下级传递)$parent
$refs
- 多级组件上下级
provide
inject
- 跨级、全局
- 自定义事件
- Vuex