写这篇文章之前,我对vue组件之间的传值,还是只知道一些基础的传值方式。虽然工作中勉强能够应对,但是想要行云流水感觉还是心有余而力不足,所以在此,我想总结一下vue组件之间的一些传值方式供大家参考,同时也是给自己加深下记忆。
vue的传值方式大概分为以下几种
- 父传子
- 子传父
- 兄弟间
- 隔代传参
首先我们介绍下第一种 父传子:
父传子方式1:最常用的就是props传值,这种方式大家都很熟悉,但是也有点小坑,比如父组件没有传递某一个值过来而子组件缺定义了这个值,这时候我们就需要设置默认值的方式解决该问题的出现,具体代码如下
//这是父组件 就叫father.vue
<template>
<div id="father">
<child :unit=unit></child>
</div>
</template>
<script>
import child from './child.vue'
export default {
data(){
return {
unit:'this is a unit'
}
},
components:{child }
}
</script>
//这是一个子组件 就叫child.vue
<template>
<div id="child">
<p>unit:{{unit}}</p>
</div>
</template>
<script>
export default {
props: ['items', 'unit'] //注意这里父组件暂没有传items
}
</script>
如果items在父组件中没有传值,并且在child.vue里面接收且想要的是字符转类型的我们可以这么操作
//这是父组件 就叫father.vue
<template>
<div id="father">
<child :unit=unit></child>
</div>
</template>
<script>
import child from './child.vue'
export default {
data(){
return {
unit:'this is a unit'
}
},
components:{child }
}
</script>
//这是一个子组件 就叫child.vue
<template>
<div id="child">
<p>unit:{{unit}}</p>
</div>
</template>
<script>
export default {
props: {
items: {
type: String,
required: true, // 必须提供字段
default:'this is a default' //这是第一种写法
},
unit: { // 可选字段,有默认值
type: String,
default:()=>{
return 'this is a default' // 这是第二种写法
}
}
}
}
</script>
//以上是传字符串的方式,其他类型类似,但是数组除外,如果是数组就要采用以下形式
array:{
type: Array,
default: function () { //这里也可以使用箭头函数的方式 和以上第二种形式类似
return []
}
}
父传子方式2:$refs
$refs 利用ref标识组件,通过事件传参把数据传给子组件,数据相互独立
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue $ref</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<div id="app">
</div>
<script>
Vue.component("parent",{
data(){
return{
parentMsg:"我是父组件数据parent"
}
},
template:`<div>
<h3>父组件:{{parentMsg}}</h3>
<button @click="send">点击改变子组件的数据</button><br/>
<button @click="changSlef">点击改变父组件数据,但子组件的数据不变哦</button>
<child ref="child"></child>
</div>`,
methods:{
send:function(){
this.$refs.child.changeChild(this.parentMsg); //this.$refs.child 代表child组件。changeChild方法对应的child组件里面的changeChild方法 数据传参的形式传给子组件
},
changSlef:function(){
this.parentMsg="我是父组件数据,我发生改变了"
}
}
})
Vue.component("child",{
data() {
return {
childMsg:"我是子组件数据child"
}
},
template:`<div>
<h4>子组件:{{ childMsg }}</h4>
</div>`,
methods: {
changeChild:function(val){
this.childMsg=val; // 传参后接受,改变子组件的值
}
},
})
new Vue({
el:"#app",
template:`<div>
<parent></parent>
</div>`
})
</script>
</body>
</html>
父传子方式3:$attrs
$attrs通过绑定属性,来实现传值;可以实现,父传子,孙组件;$attrs是vue2.4版本提出的方法
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue $attrs</title>
<script src="https://cdn.staticfile.org/vue/2.4.0/vue.min.js"></script>
</head>
<body>
<div id="app"></div>
<script>
Vue.component("component-c",{
inheritAttrs:false, //继承所有的父组件属性(除了prop传递的属性、class 和 style )
template:`<div>
<h5>c组件:{{$attrs.c}}</h5>
</div>`
})
Vue.component("component-b",{
inheritAttrs:false, //继承所有的父组件属性(除了prop传递的属性、class 和 style )
template:`<div>
<h2>$attrs传递的值:{{$attrs.b}}</h2>
<component-c v-bind="$attrs"></component-c>
</div>`
//v-bind="attrs";绑定属性,是c组件可以接收a逐渐传值 注意注意注意注意
})
Vue.component("component-a",{
data () {
return {
aMsg:"组件a",
msgB:"组件a传给b的值",
msgC:"组件a传给c的值",
d:"默认值"
}
},
template:`<div>
<h1>a组件:{{ aMsg }}</h1>
<component-b :b="msgB" :c="msgC" ></component-b>
</div>`
})
var app=new Vue({
el:'#app',
template:`<div>
<component-a></component-a>
</di> `
})
</script>
</body>
</html>
父传子方式4:$children[0]
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue $children</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<div id="app">
</div>
<script>
Vue.component("parent",{
data(){
return{
parentMsg:"我是父组件数据parent"
}
},
template:`<div>
<h3>父组件:{{parentMsg}}</h3>
<child></child>
</div>`,
mounted(){
this.$children[0].childMsg = 'hahah'+ this.parentMsg //改变子组件的childMsg的值
},
methods:{}
})
Vue.component("child",{
data() {
return {
childMsg:"我是子组件数据child"
}
},
template:`<div>
<h4 >子组件:{{ childMsg }}</h4>
</div>`,
methods: {},
})
new Vue({
el:"#app",
template:`<div>
<parent></parent>
</div>`
})
</script>
</body>
</html>
以上是父传子的四种方式,可以根据需要自己选择,$attrs既可以实现父传子,又可以实现父传孙实现隔代传
接下来我们介绍下第二种 子传父:
常用的就是$emit,具体代码如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue $ref</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<div id="app">
</div>
<script>
Vue.component("parent",{
data(){
return{
parentMsg:"我是父组件数据parent"
}
},
template:`<div>
<h3>父组件:{{parentMsg}}</h3>
<button @click="send">点击改变子组件的数据</button><br/>
<button @click="changSlef">点击改变父组件数据,但子组件的数据不变哦</button>
<child ref="child" @parentClick="parentClick"></child>
</div>`,
methods:{
send:function(){
this.$refs.child.changeChild(this.parentMsg);
},
changSlef:function(){
this.parentMsg="我是父组件数据,我发生改变了"
},
parentClick:function(val){ //父接受子传来的值,改变父
this.parentMsg = val
}
}
})
Vue.component("child",{
data() {
return {
childMsg:"我是子组件数据child"
}
},
template:`<div>
<h4 @click="changeParent">子组件:{{ childMsg }}</h4>
</div>`,
methods: {
changeChild:function(val){
this.childMsg=val;
},
changeParent:function(){ //子改父用emit传值
this.$emit("parentClick" , this.childMsg)
},
},
})
new Vue({
el:"#app",
template:`<div>
<parent></parent>
</div>`
})
</script>
</body>
</html>
以上是子传父,如果大家还有其他的方式,欢迎以下留言,我再补上去,感谢
继续我们介绍下第三种 兄弟间:(这个有点意思了)
兄弟间传值需要创建一个新的js文件,内容不多就是如下两行代码,但是百度的时候大家可能看到有两种一个是eventVue.js一个是bus.js,其实内容是一样,只不过名字不同而已。在这里我就叫做bus.js,然后用$emi触发传参,$on去接收赋值。原理就是类似window的全局自定义事件,利用一个新的vue示例作为媒介,而不是当前vue示例(this)
import Vue from 'vue'
export default new Vue()
创建好了bus.js后,具体代码如下
<template>
<components-a></components-a> //组件A
<components-b></components-b> //组件B
</template>
//组件A
<template>
<div class="components-a">
<button @click="abtn">A按钮</button>
</div>
</template>
<script>
import bus from '../../js/bus.js'
export default {
name: 'app',
data () {
return {
'msg':"我是组件A"
}
},
methods:{
abtn:function(){
bus.$emit("myFun",this.msg) //$emit这个方法会触发一个事件
}
}
}
</script>
//组件B
<template>
<div class="components-a">
<div>{{btext}}</div>
</div>
</template>
<script>
import bus from '../../js/bus.js'
export default {
name: 'app',
data () {
return {
'btext':"我是B组件内容"
}
},
created:function(){
this.bbtn();
},
methods:{
bbtn:function(){
bus.$on("myFun",(message)=>{ //这里最好用箭头函数,不然this指向有问题
this.btext = message
})
}
}
}
</script>
最后我们介绍下最后一种隔代传参
采用的是provide / inject的形式,用法和父传子的props类似,具体代码如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue provide inject</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<div id="app">
</div>
<script>
Vue.component("parent",{
data(){
return{
parentMsg:"我是父组件,现在我想改变子子组件"
}
},
provide(){
return{
parentValue:"我是父组件"
}
},
template:`<div>
<h3>父组件:{{parentMsg}}</h3>
<child></child>
</div>`,
methods:{
}
})
Vue.component("child",{
data() {
return {
childMsg:"子组件"
}
},
template:`<div>
<h4>子组件:{{ childMsg }}</h4>
<third></third>
</div>`,
methods: {
},
})
Vue.component("third",{
data() {
return {
childMsg:"子子组件"
}
},
inject:['parentValue'],
template:`<div>
<h4>子子组件:{{ childMsg }}</h4>
</div>`,
mounted(){
this.childMsg = this.parentValue
},
})
new Vue({
el:"#app",
template:`<div>
<parent></parent>
</div>`
})
</script>
</body>
</html>
在定义父组件的时候用provide方法和data一样通过return 返回,在组件里需要改变的时候用inject 用法和props一样包括设置默认值的方式.
以上是组件之间的全部传参方式,包含了父转子,子传父,同级别之间的传参,跨级别传参的方法,如有不足之处还望指出,再加修改