一、组件间通信传值的各种方式与场景
1、父组件向子组件(跨级)传值
1.1 父组件通过props给子组件传值
props也可以传函数
// 父组件vue文件
<template>
<div class="home">
<!--父组件传msg属性给子组件传值-->
<child :msg="msg"></child>
</div>
</template>
<script>
import Child from '@/components/Child'
export default {
name: 'Father',
components: {
Child
},
data () {
return {
msg: '父组件传给子组件的值'
}
},
methods: {}
}
</script>
// 子组件
<template>
<div>{{ msg }}</div>
</template>
<script>
export default {
name: 'Child',
// 子组件通过props接收父组件的传值
props: ['msg']
}
</script>
<style scoped>
</style>
1.2 父组件通过$ref给子组件传值
ref 用于给元素或子组件注册引用信息,引用信息将会注册在父组件的 refs 对象上,父组件通过refs对象上,父组件通过ref 获取到在子组件里定义的属性和方法,通过调用方法给子组件传递数据
// 父组件
<template>
<div class="home">
<!--父组件传msg属性给子组件传值-->
<child ref="child"></child>
</div>
</template>
<script>
import Child from '@/components/Child'
export default {
name: 'Father',
components: {
Child
},
data () {
return {
msg: '父组件传给子组件的值'
}
},
mounted () {
// 父组件通过ref属性调用子组件的方法
this.$refs.child.getMsg(this.msg)
},
methods: {}
}
</script>
// 子组件
<template>
<div>{{ msg }}</div>
</template>
<script>
export default {
name: 'Child',
data () {
return {
msg: ''
}
},
methods: {
// 子组件获取父组件值的方法
getMsg (val) {
this.msg = val
}
}
}
</script>
<style scoped>
</style>
1.3 父组件通过$children给子组件传值
children为当前组件的直接子组件,是一个无序的数组,父组件通过 children 访问子组件并传递数据,$ children
并不保证顺序,也不是响应式的,如果能清楚的知道子组件的顺序,可以使用下标来操作对应的子组件
// 父组件
<template>
<div class="home">
<!--父组件传msg属性给子组件传值-->
<child ref="child"></child>
</div>
</template>
<script>
import Child from '@/components/Child'
export default {
name: 'Father',
components: {
Child
},
data () {
return {
msg: '父组件传给子组件的值'
}
},
mounted () {
// 父组件通过$children[0]访问对应子组件
this.$children[0].msg = this.msg
},
methods: {}
}
</script>
// 子组件
<template>
<div>{{ msg }}</div>
</template>
<script>
export default {
name: 'Child',
data () {
return {
msg: ''
}
}
}
</script>
<style scoped>
</style>
1.4 父组件通过provide/inject给子孙组件传值
provide/inject 组合以允许一个祖先组件向其所有子孙后代组件注入一个依赖(属性和方法),不论组件层次有多深,并在其上下游关系成立的时间里始终生效,从而实现跨级父子组件通信,主要在开发高阶插件/组件库时使用
// 父组件
<template>
<div class="home">
<child></child>
</div>
</template>
<script>
import Child from '@/components/Child'
export default {
name: 'Father',
components: {
Child
},
data () {
return {}
},
// 父组件通过provide方法向子孙组件提供值
provide () {
return {
msg: '父组件传给子组件的值'
}
}
}
</script>
// 子组件
<template>
<div>{{ msg }}</div>
</template>
<script>
export default {
name: 'Child',
// 子孙组件通过inject注入父组件提供的值
inject: ['msg'],
data () {
return {
}
}
}
</script>
<style scoped>
</style>
总结:props
和$ref
和 $children
和provide/inject
的主要区别:
- props 侧重于数据的传递,并不能获取子组件里的属性和方法,适用于自定义内容的使用场景
-
$ref
侧重于获取子组件里的属性和方法,并不是太适合传递数据,并且 ref 常用于获取dom元素,起到选择器的作用 -
$children
侧重于获取所有的直接子组件,得到的是一个无序的数组,并不太适合向多个子组件传递数据 - provide/inject 侧重于在开发高阶插件/组件库时使用,并不推荐用于普通应用程序代码中。
1.5 非prop的$attrs?inheritAttrs? 提供封装组件的可扩展性
要求第1个input输入文字,第2个input输入密码
-
设置 inheritAttrs: false
-
v-bind="$attrs"
-
总结
// 子组件
<template>
<div class="input-con">
<input v-bind="$attrs" :value="value" @input="$emit('input')">
$attrs接收非props传递过来的属性:{{$attrs}},所有不包含属性 ’value‘
</div>
</template>
<script>
export default {
name: 'Child',
props: ['value'],
inheritAttrs: false // 关闭父组件传过来的属性添加到子组件的根元素
}
</script>
<style scoped>
</style>
// 父组件
<template>
<div class="home">
<!--要求第1个input输入文字-->
<!-- 第2个input输入密码-->
<child v-model="msg" type="text"></child>
<child v-model="msg" type="password"></child>
</div>
</template>
<script>
import Child from '@/components/Child'
export default {
name: 'Father',
components: {
Child
},
data () {
return {
msg: '你好,孩子'
}
}
}
</script>
1.6 $listeners
包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
2、子组件向父组件(跨级)传值 $emit(自定义事件名[,...param])
2.1 子组件通过触发$emit事件给父组件传值
$emit
的第一个参数为自定义的事件,第二个参数为要传递给父组件的值,父组件在子组件标签上绑定自定义事件来接收子组件传递的数据
// 子组件
<template>
<div>
<button @click="sendMsg"></button>
</div>
</template>
<script>
export default {
name: 'Child',
data () {
return {
msg: '子组件传给父组件的值'
}
},
methods: {
sendMsg () {
this.$emit('getMsg', this.msg)
}
}
}
</script>
<style scoped>
</style>
// 父组件
<template>
<div class="home">
<child @getMsg="getData"></child>
<p>{{msg}}</p>
</div>
</template>
<script>
import Child from '@/components/Child'
export default {
name: 'Father',
components: {
Child
},
data () {
return {
msg: ''
}
},
methods: {
getData (data) {
this.msg = data
}
}
}
</script>
2.2 子组件通过$parent给父组件传值
$parent
可以用来从一个子组件访问父组件并传递数据
// 子组件
<template>
<div>
<button @click="sendMsg"></button>
</div>
</template>
<script>
export default {
name: 'Child',
data () {
return {
msg: '子组件传给父组件的值'
}
},
methods: {
// 子组件通过$parent访问父组件
sendMsg () {
this.$parent.msg = this.msg
}
}
}
</script>
// 父组件
<template>
<div class="home">
<child></child>
<p>{{msg}}</p>
</div>
</template>
<script>
import Child from '@/components/Child'
export default {
name: 'Father',
components: {
Child
},
data () {
return {
msg: ''
}
}
}
</script>
3、兄弟组件间通信传值 vm.$emit
和vm.$on
兄弟之间传值通过eventBus。
eventBus 就是一个vue实例来作为全局的事件总线,兄弟组件之间通过 eventBus. on 和 eventBus.on和eventBus.emit 注册触发事件来传递数据
// 新建一个vue实例 eventBus.js
import Vue from 'vue'
export default new Vue()
// 父组件
<template>
<div class="home">
<child></child>
<child-two></child-two>
</div>
</template>
<script>
import Child from '@/components/Child'
import ChildTwo from '@/components/ChildTwo'
export default {
name: 'Father',
components: {
Child,
ChildTwo
},
data () {
return {
msg: ''
}
}
}
</script>
// 子组件A
<template>
<div>
<button @click="sendMsg">子组件A传值给子组件B</button>
</div>
</template>
<script>
import eventBut from '@/utils/eventBut'
export default {
name: 'Child',
data () {
return {
msg: '子组件A传给子组件B的值'
}
},
methods: {
sendMsg () {
// 子组件A通过eventBus.$emit触发自定义事件给子组件B传值
eventBut.$emit('getMsg', this.msg)
}
}
}
</script>
<style scoped>
</style>
// 子组件B
<template>
<div>
{{ msg }}
</div>
</template>
<script>
import eventBut from '@/utils/eventBut'
export default {
name: 'ChildTwo',
data () {
return {
msg: ''
}
},
created () {
this.getData()
},
methods: {
getData () {
eventBut.$on('getMsg', (data) => {
this.msg = data
})
}
}
}
</script>
<style scoped>
</style>