当做到比较大的项目时,一个vue文件里面可能要包含上千行代码,这样不利于后期维护与问题定位,抽离成组件就尤其重要了,重中之重的就是组件之间数据传递的几种方式。
父子传参、子父传参、兄弟传参、事件总线/事件车(EventBus)、Vuex。
父子传参
父元素将值通过自定义属性传递给子元素,子元素通过props:['属性名']接收父元素传递过来的值。
父组件
<template>
<div class="wrap">
<div>我是Father组件</div>
<Son
str="我是字符串"
:num=5
:obj="{cont:'我是一个对象'}"
:func="()=>{this.hello()}"
:arr="arr"></Son>
</div>
</template>
<script>
import Son from './Son'
export default {
name: "Father",
components:{ Son },
data(){
return{
arr:[1,2,3]
}
},
methods:{
hello(){
console.log("hello world!")
}
},
}
</script>
子组件
<template>
<div>我是Son组件</div>
</template>
<script>
export default {
name: "Son",
props:{//props列表
arr:Array,//定义参数类型
num:Number,
str:String,
str2:{
type:String,
default:"我是默认字符串"//定义参数默认值
},
func:{
type:Function,
required:false//定义参数是否必须值
},
obj:{
type: Object,
required:false
}
},
created() {
console.log(this.str);//我是字符串
console.log(this.str2);//我是默认字符串
console.log(this.num);//5
console.log(this.func);//hello(){console.log("hello world!");}
console.log(this.arr);//[1,2,3]
console.log(this.obj);//{cont:'我是一个对象'}
this.func();//hello world!
}
}
</script>
子父传参
Vue的设计是单向数据流,理论上只允许父组件向子组件传递数据。想通过子组件向父组件传参必须是父元素传递一个事件给子组件,子组件通过父组件传递的方法进行传参,主要使用$emit('事件名',参数)。
//父组件App.vue
<template>
<div>
//在子组件绑定一个自定义事件名但是不能与系统事件重名
<son @goSon="receiveMsg"/>
<span>收到子组件传递的参数:{{num}}</span>
</div>
</template>
<script>
import MyCom from './components/MyCom.vue'
export default {
components: { Son },
data(){
return{
num:'' //用于接收子元素传递的信息
}
},
methods: {
receiveMsg(msg) {
console.log('子传入的信息:', msg);
this.num =msg
}
},
}
</script>
子组件:Son.vue
<template>
<div>
<button @click="chooseNum(1)">传参</button>
</div>
</template>
<script>
export default {
methods: {
chooseNum(num){
//1.父元素需要传递一个方法给子元素
//父元素: @suibian="receiveMsg"
//2.子元素利用父元素传递的方法 来传递信息给父元素
// 使用 $emit 来触发自定义事件
// 参数1: 事件名
// 参数2: 传递给事件中绑定方法的 参数
this.$emit('receiveMsg', num)
}
},
}
</script>
兄弟传参
兄弟传参依赖于父组件,兄弟A将参数传递给父,父将参数传递给兄弟B。
创建子组件1 FirstCom.vue
<template>
<div class="first-com">
<h1>第一个组件</h1>
<input type="text" v-model="num">
<button @click="doSure">传递</button>
</div>
</template>
<script>
export default {
data() {
return {
num: ''
}
},
methods: {
doSure() {
//简单方式--不推荐
// this.$parent.first_kw = this.num
// 优雅方式 -- 通过父传递的方法进行传参
this.$emit('sendMsg',this.kw)
}
},
}
</script>
<style lang="scss" scoped>
.first-com{
background-color: green;
min-height:200px
}
</style>
创建子组件2 SecondCom.vue
<template>
<div class="first-com">
<h1>第一个组件</h1>
<p>来自父元素的传参:{{kw}}</p>
</div>
</template>
<script>
export default {
props:['kw']
}
</script>
<style lang="scss" scoped>
.first-com{
background-color: blue;
min-height:200px
}
</style>
父组件为App.vue
<template>
<div>
<p>来自子元素firstCom的值:{{first_kw}}</p>
<first-com @sendMsg="receiveMsg"/>
<second-com :kw="first_kw"/>
</div>
</template>
<script>
import FirstCom from './components/FirstCom.vue'
import SecondCom from './components/SecondCom.vue'
export default {
components: { FirstCom, SecondCom },
data() {
return {
first_kw: '', //来自子元素firstCom的值
}
},
// 优雅的 子传父 : 1.父声明方法传递给子 2.子调用父传入的方法
methods: {
receiveMsg(msg) {
this.first_kw = msg
}
},
}
</script>
事件总线/事件车
在需要传递参数的组件中通过$root.$emit('自定义的名称',要传递的参数)来向外发布消息。
<template>
<div>
<button @click="chooseNum(1)">One</button>
<button @click="chooseNum(2)">Two</button>
<button @click="chooseNum(3)">Three</button>
</div>
</template>
<script>
export default {
methods: {
chooseNum(num) {
console.log('this:', this);
// this.$root: 是所有组件的根
// 在 $root 中向外发布消息, 就可以被所有的组件接收到
// 参数1: 自定义的值, 随便写
// 参数2: 与参数1名称绑定的相关信息
this.$root.$emit('哈哈', {msg:"消息内容", num})
}
},
}
</script>
需要接收参数的组件通过$root.$on('发送消息组件自定义的名称',msg=>{在这处理接收到的消息})监听消息,接收完毕后在组件销毁前beforeDestroy中关闭监听$root.$off('自定义名称')。
<template>
<div>
<!-- 事件车: Event Bus -->
<!-- 可以实现: 任意关系的多个组件间的消息传递 -->
<my-com-bus/>
</div>
</template>
<script>
import MyComBus from './components/MyComBus.vue'
export default {
components: { MyComBus },
mounted () {
// 监听 根元素 $root 中发送的消息
// 参数1: 要听的消息名
this.$root.$on('哈哈', function (data) {
// data: 就是 $emit('哈哈', 具体数据data)
console.log('收到的具体信息:', data);
})
},
beforeDestroy () {
// 通常: 在销毁前会 关闭监听
this.$root.$off('哈哈')
},
}
</script>
评论