这次在做项目的时候又遇到了组件通信的问题,还是自己不太理解这其中的奥秘,平时用的也比较少。所以在开发中才会多次遇到问题,这次做个总结吧,希望对以后会有帮助!
需求是这样:一个tab切换的组件,需要在一个页面中调用两次,当改变其中一个的状态的时候另外一个也要跟着改变。
组件中的列表是通过父组件传递过来的。
最开始我的做法是这样:
step1:通过props获取父组件的值将tab列表渲染
step2:在computed中设置defaultId为列表第一项的id
step3:tab激活状态的条件是id == defaultId
代码大致长这样:
<template>
<div>
<span v-for="tab in tabs"
:key="tab.id"
:class="{active: defaultId == tab.id}
@click="switchTab(tab.id)""></span>
</div>
</template>
export default {
props: {
tabs: Array
},
computed: {
defaultId () {
return this.tabs[0].id
}
},
methods: {
switchTab (id) {
this.defaultId = id
}
}
}
这里存在两个错误:
1.要修改defaultId的值需要在computed中设置set,详见官网
2.defaultId的变化需要的是它的依赖发生变化,才会触发,也就是这里的tabs
尝试失败后,我又把computed改成了data。
<template>
<div>
<span v-for="tab in tabs"
:key="tab.id"
:class="{active: defaultId == tab.id}
@click="switchTab(tab.id)""></span>
</div>
</template>
export default {
props: {
tabs: Array
},
data () {
defaultId: this.tabs[0].id
},
methods: {
switchTab (id) {
this.defaultId = id
}
}
}
换成data后惊喜的发现,点击的组件状态是客户发生变化的,好开心啊!然后再仔细一看事情并不是那么简单,另外一个组件的状态居然没发生变化???不都是公用的defaultId吗?这是怎么回事?仔细回想了一番原来是这样。数据再data中使用函数的形式返回,就相当于这个数据只在这个组件中起作用,类似一个组件作用域,虽然这个组件在页面中复用了两次,但是每次都是一个独立的组件,互不干涉。
一番摸索还不成功,最后在同事的提醒下才恍然大悟,defaultId可以直接从父组件中传递,改变defaultId可以使用$emit $on触发。具体代码如下:
<template>
<div>
<span v-for="tab in tabs"
:key="tab.id"
:class="{active: defaultId == tab.id}
@click="switchTab(tab.id)""></span>
</div>
</template>
export default {
props: {
tabs: Array,
defaultId: Number
},
methods: {
switchTab (id) {
this.$emit('switch-id', id)
}
}
}
// 父组件
<template>
<child :tabs='xxx' :defaultId="xxx" @switch-id="changeId"></child>
</template>
export default {
props: {
tabs: Array,
defaultId: Number
},
methods: {
changeId (data) {
this.defaultId = data
}
}
}
这样改变props中的defaultId就可以同时触发两个组件中的状态了。
总结:
1.不管组件通信中改变数据状态要从源头上改变(父组件),不要在父组件重尝试改变props的值。
2.要学会使用$emit $on
tips:
1.组件传参的时候如果父组件的传过来的值是接口返回的,这是子组件已经渲染了但是父组件还没有这个值,所以在子组件中就接收不到。这种情况下就在父组件加一个v-if判断,当有值时才渲染子组件。
2.$emit传参到父组件,父组件接收这个参数并且自己还要传参数的时候可以使用$event
// 父组件
<template>
<child :tabs='xxx' :defaultId="xxx" @switch-id="changeId($event, 1)"></child>
</template>
export default {
props: {
tabs: Array,
defaultId: Number
},
methods: {
changeId (data, type) {
this.defaultId = data
console.log(type) // 1
}
}
}
或者:这里(还没看太懂)