Vue/Nuxt已有选中项数组如何初始化点击状态避免二次点击问题
解决方案
核心问题原因
你的问题本质是出现了重复数据源:选中状态的可信来源本该是父组件的selectedItems数组,但你又在子组件内部单独维护了clicked状态,两个状态初始化时没有做同步,就导致默认选中的项,子组件内部clicked还是false,第一次点击会把clicked切为true触发新增事件,第二次点击才会切为false触发删除,出现需要点击两次的问题。
推荐方案:使用单向数据流,移除子组件内部冗余状态
不要让子组件自己维护选中状态,所有选中判断完全依赖父组件传入的选中标识,保证唯一数据源,从根本上避免不同步问题。
修改后代码
子组件代码
Vue.component('Item', { template: ` <div> <div :class="{'clicked': isSelected}" @click="selectItem()"> {{item.name}} </div> </div> `, props: { item: { type: Object, default: null, }, // 新增prop,由父组件传入当前项是否被选中 isSelected: { type: Boolean, default: false } }, methods: { selectItem() { // 不需要自己维护状态,直接把当前选中状态反向传给父组件处理 if (this.isSelected) { this.$emit('remove-item', this.item.id) } else { this.$emit('add-item', this.item) } }, }, })
父组件调用代码
<div id="demo"> <template> <div v-for="item in items" :key="item.id"> <Item :item="item" :is-selected="selectedItems.some(i => i.id === item.id)" @add-item="addItemToArray" @remove-item="removeItemFromArray" > </Item> </div> </template> </div>
原有CSS和父组件逻辑不需要修改
.clicked {background-color: coral;}
new Vue({ el: '#demo', data() { return { items: [{id: 1, name: 'a'}, {id: 2,name: 'b'}, {id: 3, name: 'c'}], selectedItems: [{id: 2, name: 'b'}], } }, methods: { addItemToArray(clickedItem){ this.selectedItems = [...this.selectedItems, clickedItem] }, removeItemFromArray(id){ this.selectedItems = this.selectedItems.filter( (clickedItem) => clickedItem.id !== id ) }, } })
备选方案:子组件维护状态时的同步方案
如果你确实需要在子组件内部维护clicked状态,可以在子组件初始化时同步父组件的选中状态:
- 父组件调用时传入
isSelected标识 - 子组件
mounted钩子中,根据传入的选中值初始化clicked
如果后续父组件selectedItems可能被外部修改,还需要增加watch监听isSelected变化同步更新clicked,避免出现不同步问题。该方案冗余度高,更推荐使用第一种单向数据流方案。
// 子组件核心修改部分 props: { item: Object, isSelected: Boolean }, data() { return { clicked: false } }, mounted() { // 初始化时同步父组件的选中状态 this.clicked = this.isSelected }
内容的提问来源于stack exchange,提问作者itsmeagian
相关产品推荐
相关产品推荐

