问题描述: 子组件中通过点击事件修改DOM元素中的selected选中项,数组中被选中的数据值更新了,但是视图未更新选中的样式
// 子组件
<view class="option">
<view
v-for="(item, index) in options.items"
:key="index"
class="item"
:class="item.current ? 'selected' : ''"
@tap="onClickItem(index)">
<view class="item-t">{{ item.name }}</view>
<view class="price"><text v-if="!options.showImg">¥</text>{{ item.price }}</view>
</view>
</view>
const emit = defineEmits(['update:options'])
const onClickItem = (index) => {
props.options.items.forEach((item, i) => {
if (index === i) {
item.current = !item.current
} else {
item.current = false
}
})
emit('update:options', props.options)
}
// 父组件
const options= ref({
desc: '请选择',
items: [
{ name: '选项一', price: '0.00', current: true },
{ name: '选项二', price: '2.00', current: false },
{ name: '选项三', price: '4.00', current: false },
{ name: '选项四', price: '6.00', current: false },
{ name: '选项五', price: '8.00', current: false },
{ name: '选项六', price: '10.00', current: false },
],
showImg: false,
})
<ChildComponent
v-model:options="options"
@update:options="options = $event"
/>
onClickItem点击事件时,options.item里面的current的值更新了,但是视图中selected选中样式并未更新。
这是因为:在子组件中,虽然修改了 props.options 的值,但是 Vue 的 Props | 单向数据流特性
会阻止修改 prop
要让选中的项生效,可以:
- 不要用 prop 传递 options,直接在子组件中用一个 ref 声明 options
- 子组件中 emit 一个新选中的索引值,父组件根据这个索引更新自己的 options
这样就可以避免子组件直接修改父组件的状态了。
例如:
// 子组件
const emit = defineEmits(['update:selected'])
const selectedIndex = ref(0)
const onClickItem = (index) => {
selectedIndex.value = index
emit('update:selected', index)
props.options.items.forEach((item, i) => {
if (index === i) {
item.current = !item.current
} else {
item.current = false
}
})
}
// 父组件
<ChildComponent
v-model:selected="selectedIndex"
@update:selected="index => {
options.items[index].current = true
options.items.forEach(item => {
if(item !== options.items[index]) {
item.current = false
}
})
}"
/>
最终效果如图所示: