谈到vue,肯定离不开vue组件之间传值,组件间传值主要分为父子组件传值,兄弟组件传值,任意组件间传值,通过这篇文章总结一下vue组件之间传值的几个方式。
1、父子组件之间传值
父传子
(1)props和attrs
父组件Parent
<template>
<div>
<Child1 :msgProps="msgProps" :msgAttrs="msgAttrs"/>
</div>
</template>
<script>
import Child1 from './Child1.vue'
export default {
components: { Child1 },
data() {
return {
msgProps: "我是用props接收的",
msgAttrs: "我是没有用props接收传的值",
}
},
}
</script>
子组件Child1
<template>
<div>
<p>{{msgProps}}</p>
<p>{{$attrs.msgAttrs}}</p>
</div>
</template>
<script>
export default {
props: {
msgProps: {
type: String,
default: "我是默认的"
}
},
}
</script>
父组件向子组件传值的时候如果子组件中在props中声明接收了,则在子组件中可以直接使用,如果没有声明接收则传递的值是存储在子组件实例的$attrs(Object)属性上的,需要通过 $attrs去获值。
(2)$parent
父组件Parent
<template>
<div>
<Child1/>
</div>
</template>
<script>
import Child1 from './Child1.vue'
export default {
components: { Child1},
data() {
return {
msgChildren: "我是通过$children获取的值"
}
},
}
</script>
<style>
</style>
子组件Child1
<template>
<div>
<p>{{msg}}</p>
</div>
</template>
<script>
export default {
data() {
return {
msg: ""
}
},
created() {
this.msg = this.$parent.msgChildren
}
}
</script>
子组件的实例上有个 $parent属性,上面存储着父组件的一些信息,可以同过 $parent获取父组件中的值,甚至还可以调用父组件中的方法,下面介绍的兄弟组件间的传值就是利用这个特性进行兄弟组件间传值的。
(3)provide/inject
父组件Parent
<template>
<div>
<Child1/>
</div>
</template>
<script>
import Child1 from './Child1.vue'
export default {
components: { Child1},
provide(){
return{
msg: this.msg
}
},
data() {
return {
msg: "通过provide传值"
}
},
}
</script>
子组件Child1
<template>
<div>
<p>{{msg}}</p>
</div>
</template>
<script>
export default {
inject: ["msg"],
data() {
return {
}
},
}
</script>
把provide/inject放在这个地方有些不合适,因为provide/inject主要是用来祖先组件向子孙组件传值的,只要在祖先组件中使用provide提供依赖,不管多深层,只要是该祖先组件的子孙组件都可已通过inject接收。
子传父
(1) $emit
子组件Child1:
<template>
<div>
<p>我是child1</p>
<button @click="toParent">点我传值给父组件</button>
</div>
</template>
<script>
export default {
data() {
return {
child1: "我是child1传给parent的值"
}
},
methods: {
toParent() {
this.$emit("toParent", this.child1)
}
}
}
</script>
父组件Parent:
<template>
<div>
<p>我是parent组件</p>
<Child1 @toParent="getParent"/>
</div>
</template>
<script>
import Child1 from './Child1.vue'
import Child2 from "./Child2.vue"
export default {
components: { Child1, Child2 },
data() {
return {
msg: ""
}
},
methods: {
getParent(data) {
this.msg = data; //将子组件传来的值赋值给msg
}
}
}
</script>
子组件可以使用 $emit 触发父组件的自定义事件,所以子组件可以使用 $emit像父组件传值。
(2)$children
子组件Child1
<template>
<div>
<p>我是child1</p>
</div>
</template>
<script>
export default {
data() {
return {
child1: "我是child1"
}
},
}
</script>
子组件Child2:
<template>
<div>
<p>我是child2</p>
</div>
</template>
<script>
export default {
data() {
return {
child2: "我是child2"
}
},
methods: {
getChild2() {
console.log(this.child2)
}
}
}
</script>
父组件Parent:
<template>
<div>
<p>我是parent组件</p>
<child1/>
<child2/>
<button @click="getData">获取子组件的值</button>
<button @click="clickChild2">触发子组件Child2中的方法</button>
</div>
</template>
<script>
import Child1 from './Child1.vue'
import Child2 from "./Child2.vue"
export default {
components: { Child1, Child2 },
methods: {
getData() {
console.log(this.$children[0].child1); //输出"我是child1"
console.log(this.$children[1].child2); 输出"我是child1"
},
clickChild2() {
this.$children[1].getChild2();
}
}
}
</script>
组件实例上有$children属性,如果输出 $children你会发现返回的是一个由当前组件子组件实例组成数组,所以找到子组件在当前组件 $Children中的位置,就可以在当前组件中访问子组件中的数据,还可以调用子组件中的方法。
(3)ref
子组件Child2:
<template>
<div>
<p>我是child2</p>
</div>
</template>
<script>
export default {
data() {
return {
child2: "我是child2"
}
},
methods: {
getChild2() {
console.log(this.child2)
}
}
}
</script>
父组件Parent
<template>
<div>
<p>我是parent组件</p>
<child2 ref="child2"/>
<button @click="getData">获取子组件的值</button>
<button @click="clickChild2">触发子组件Child2中的方法</button>
</div>
</template>
<script>
import Child1 from './Child1.vue'
import Child2 from "./Child2.vue"
export default {
components: { Child1, Child2 },
methods: {
getData() {
console.log(this.$refs.child2.child2); 输出"我是child1"
},
clickChild2() {
this.$refs.child2.getChild2();
}
}
}
</script>
在父组件中给子组件添加ref属性,然后通过$refs.来获取当前子元素的实例,所以通过ref也可以在父组件中访问子组件中的数据,还可以调用子组件中的方法。
2、兄弟组件之间的传值
(1)EventBus(事件总线)
新建一个 js 文件
import Vue from 'vue'
export default new Vue;
main.js中引入该文件
import eventBus from './utils/eventBus'
Vue.prototype.eventBus = eventBus;
Child1组件
<template>
<div>
<p>我是child1</p>
<button @click="send">eventBus传值</button>
</div>
</template>
<script>
export default {
data() {
return {
child1: "我是child1"
}
},
methods: {
send() {
this.eventBus.$emit("eventBusName", this.child1);
}
}
}
</script>
Child2组件
<template>
<div>
<p>我是child2</p>
</div>
</template>
<script>
export default {
data() {
return {
child2: "我是child2"
}
},
mounted() {
this.eventBus.$on('eventBusName', (val) => {
console.log("这个是用eventBus传的值:"+val)
})
},
beforeDestroy() {
//销毁监听事件
this.$bus.off("addProduct");
}
}
</script>
EventBus实现组件间的传值,主要就是通过$emit派发事件,然后通过 $on监听事件,有一点需要注意的是在订阅事件的组件里,一定要在组件销毁之前把监听事件也手动销毁一下。如果不销毁,会累积多次创建监听事件,一旦在派发事件组件里触发了事件,监听事件组件就会执行多次事件。
(2)$parent
子组件Child1:
<template>
<div>
<p>我是child1</p>
<button @click="send">通过$parent传值</button>
</div>
</template>
<script>
export default {
data() {
return {
child1: "我是child1"
}
},
methods: {
send() {
this.$parent.$emit("foo", this.child1);
}
}
}
</script>
子组件Child2:
<template>
<div>
<p>我是child2</p>
</div>
</template>
<script>
export default {
data() {
return {
child2: "我是child2"
}
},
mounted() {
this.$parent.$on("foo", val => {
console.log(val)
})
},
}
</script>
父组件Parent
<template>
<div>
<p>我是parent组件</p>
<child1/>
<child2/>
</div>
</template>
<script>
import Child1 from './Child1.vue'
import Child2 from "./Child2.vue"
export default {
components: { Child1, Child2 },
}
</script>
$parent实现兄弟组件之间的传值主要是依靠兄弟组件的共同父组件,通过 $emit, $on实现事件的派发和监听。
(3)$root
$root原理和 $parent是一样的,只不过 $parent是依靠共同的父组件实现事件的派发监听, $root是通过共同的根组件实现事件的派发和监听。用法就是把 $parent换成 $root就行,这边就不用代码演示了。
任意组件传值
(1)vuex
vuex可以实现任意组件之间的通信,内容比较多,就不过介绍了。
vue组件间的传值就总结到这了,如果有什么不对的地方欢迎指正。😎