父组件代码
<template>
<div class="page_content_container">
<div class="recommand_communities_container">
<community_card v-for="(community,index) in communities" v-bind:key="index" v-bind:community="community" v-on:onclick="onChosen" />
</div>
</div>
</template>
<script>
import community_card from '../community_card.vue';
export default {
components: { community_card},
name: "page_content",
data: function () {
return {
communities:[
{
id:'1'
name:'1-C',
intro:'1-C Test',
avatar:'/1-C-avatar.jpg'
selected:true
},
{
id:'2'
name:'2-C',
intro:'2-C Test',
avatar:'/2-C-avatar.jpg'
selected:false
},
{
id:'3'
name:'3-C',
intro:'3-C Test',
avatar:'/3-C-avatar.jpg'
selected:false
},
]
}
},
methods: {
onChosen:function(communityId){
for (let index = 0; index < this.communities.length; index++) {
const element = this.communities[index];
if(element.id == communityId ){
element.selected = true;
// element.name = 'DoTest'; 有这一行 子组件的 class 会变更 ,没有则不会变更
}else{
element.selected = false
}
}
}
},
};
</script>
<style scoped>
.page_content_container {
height: 800px;
width: 100%;
display:flex;
}
.recommand_communities_container {
height: 800px;
width: 240px;
margin: 0;
padding: 0;
display: inline-block;
}
.recommand_community_post_container {
border-radius: 15px;
height: 100%;
width: 100%;
margin: 0;
padding: 0;
border-left:1px solid rgba(0, 0, 0, 0.22);
display: inline;
}
</style>
子组件
<template>
<div class="community_card_container" v-bind:class="{'selected':community.selected}" v-on:click="onclick">
<div class="community_card_avatar_container">
<img :src="community.avatar" :title="community.name" />
</div>
<div class="community_card_base_info_container">
<div>{{ community.name }}</div>
<div>{{ community.intro }}</div>
</div>
</div>
</template>
<script>
export default {
name: "community_card",
data: function () {
return {
}
},
methods: {
onclick: function () {
this.$emit('onclick',this.community.id)
},
},
props:['community']
};
</script>
<style scoped>
.community_card_container {
height: 76px;
width: 236px;
border: lightslategray 2px solid;
display: flex;
border-radius: 10px;
}
.selected{
background-color:lightskyblue ;
}
.community_card_container .community_card_avatar_container {
height: 76px;
width: 76px;
display: inline;
text-align: center;
}
.community_card_container .community_card_base_info_container {
width: 136px;
border-left:rgb(177, 171, 204) 2px solid;
}
.community_card_container .community_card_avatar_container img {
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
}
.community_card_container .community_card_base_info_container div {
height: 38px;
width: 136px;
line-height: 38px;
text-align:center;
overflow:hidden;
}
</style>
请教原因和怎么解决
使用axios 在变更数据后 使用this.$forceupdate() 重新渲染视图
子组件更新了selected的数据 父组件实际上并没有更新 而name 这些是同步更新的
1
bootvue 2021-02-02 14:27:59 +08:00
props:['community'] 这种写法 子组件 仅仅会把 props 数据 copy 一份为本地变量使用
如果希望观察到 props 的变化 子组件应该用 computed 官方文档说的很清楚 https://cn.vuejs.org/v2/guide/components-props.html#%E5%8D%95%E5%90%91%E6%95%B0%E6%8D%AE%E6%B5%81 |
2
shintendo 2021-02-02 14:30:13 +08:00
一个建议:提问时为了方便他人阅读,尽可能先整理代码,至少不要有缺少逗号这种问题,最重要的是删除所有与问题无关的干扰代码,当你最后得到一个能复现问题的最短代码时,大概率你自己就发现问题的所在了。
|
3
ZZ222ZZ 2021-02-02 14:32:40 +08:00
好像这个需要用到深度监听,如果只是 community 属性的值发生变化,props 是不会更新的
|
4
Lemeng 2021-02-02 14:33:53 +08:00
代码有点多,把不要的去掉,尽量精简,一眼就知道问题所在
|
5
chenluo0429 2021-02-02 14:39:45 +08:00
凭感觉口胡一下。
子组件响应式的监听只到 community 这一层,对于其属性的变更不会响应。解决方案是将 community 的属性分别在 props 里面传给子组件,或者子组件添加若干 computed 计算属性来监听具体属性的变化。 |
6
jadeborner 2021-02-02 14:46:13 +08:00
用 this.$set
|
7
hengshenyu 2021-02-02 14:49:18 +08:00
我本地运行了下,没有问题。className 可以响应变化。建议看看缓存?或者 vue 版本升级?
|
8
hengshenyu 2021-02-02 14:49:35 +08:00
就是少了些逗号
|
9
ragnaroks 2021-02-02 14:50:39 +08:00
复制你的代码,使用 vue-cli 运行,没有任何问题,点击后就切换为蓝色底色了
|
10
wunonglin 2021-02-02 14:53:11 +08:00
同意#5 的说话。
其次我是建议你更改子组件的状态的话就用一个 bind: selected 即可,不要包装在对象里面,不然检测不到对象变化,除非你重新赋值 community 。 可以试一下 watch,watch 有一个 deep 选项,或者试一下 computed 。 |
11
Aruforce OP @bootvue 不是,’拷贝‘这句事实错误,
@ZZ222ZZ @chenluo0429 @jadeborner @bootvue 如当前代码这种写死数据的情况,是能够根据 selected 的变更 class value 的 @shintendo @Lemeng 抱歉。。。 |
13
wunonglin 2021-02-02 14:57:48 +08:00
父组件改成
``` <community_card v-for="(community,index) in communities" :selected="community.selected" :avatar="community.avatar" :name="community.name" :intro="community.intro" /> ``` 子组件改成 ``` export default { name: "community_card", props:['selected', 'avatar', 'name', 'intro'] }; ``` 这样试试? |
14
JXS 2021-02-02 15:01:55 +08:00
data 接收 prop,然后监听一下 prop,在监听里面去把数值改变一下看可以不
|
16
hengshenyu 2021-02-02 15:13:43 +08:00
@Aruforce 因为你是从 axios 获取的数据,所以我猜测你可能没有在 data 对它进行声明。Vue 实例生成时也就没有进行代理。
Vue 需要使用的数据都需要预先声明,否则就需要使用 this.$set(),手动处理。 |
17
Curtion 2021-02-02 15:19:54 +08:00
既然写死数据那就说明不是组件传值问题引起的,你应该从其他地方入手。 我说一个可能的原因:你的 communities 变量在实际业务上可能是异步获取的,并且其中并没有 selected 属性? 考虑使用 Vue.set
|
18
Aruforce OP @hengshenyu 应该不是吧。。子组件的数据是我从父组件传递进去的。。所有的属性都有值。。peopertySetter 应该被代理了才对了
|
19
ugu 2021-02-02 15:23:07 +08:00
通过索引直接修改数据,vue 无法监听到,建议使用 splice 或者 set
|
20
Aruforce OP @Curtion 在 axios complete 的返回里面 element.selected = true 做了这个操作了
|
21
jrtzxh020 2021-02-02 15:33:23 +08:00
不考虑性能的话。最简单的方法新建一个变量 a,将 communities 深拷贝赋值给 a,遍历 a 修改 selected 后。最后重新赋值 this.communities = a
|
23
jrtzxh020 2021-02-02 15:37:56 +08:00
@jrtzxh020 或者在 onChosen 方法最后调用 this.communities = JSON.parse(JSON.stringify(this.communities)) 哈哈 不是很建议
|
24
yor1g 2021-02-02 16:22:00 +08:00
更新 element 方法不对 子组件检查不到变更
https://cn.vuejs.org/v2/api/#Vue-set |
25
Doracis 2021-02-02 16:29:10 +08:00
不看代码先凭经验说,加深度监听 deep immediate,要么父组件 this.$set
|
26
RoshanWu 2021-02-02 20:39:19 +08:00
用个定时器模拟了下 LZ 说的「从后台通过 axios 抓取的数据 」,也没看出啥异常
``` setTimeout(() => { this.communities[0].selected = false }, 3000); ``` |
27
rodrick 2021-02-02 22:21:57 +08:00
总得来说 community.id 如果要传回去的话就最好 copy 一下再传,毕竟我总觉得把 prop 去$set 响应式有点怪,专一原则上来说 prop 就作为一个父子传参读取就好了
|
28
zqx 2021-02-03 06:40:55 +08:00 via Android
总的来说就是不要推测 vue 组件什么时候会重新渲染
forceupdate 写多了会让代码不好维护,导致下一个程序员不容易从代码中追踪数据变化 你明知道 vue 组件不会响应的数据变化(几种常见情况,官网有实例),就用 watch 手动监听它(开启 deep 选项) |