如何让v-list的v-model更新后再触发v-list-item的点击事件
问题:更新v-list选中项的邮件详情信息
我用Vuetify的v-list展示邮件列表,点击列表项时会拉取邮件附件等额外信息,同时希望同步更新v-model:selected绑定的selectedEmails数组,让选中的邮件包含完整的额外信息。
列表模板代码
<v-list :disabled="selectedEmailLoading" v-model:opened="open" v-model:selected="selectedEmails" select-strategy="independent" color="primary" lines="two" item-props style="height: calc(100vh - 300px);"> <template v-for="conversation in cleanFolder"> <v-list-item v-if="conversation.length==1" v-for="email in conversation" class="rounded-lg py-5 my-2" :value="email" @click="loadEmail(conversation[0])"> <template v-slot:prepend="{ isActive }"> <v-list-item-action start> <v-avatar color="primaryLighten1"> <span class="text-subtitle-1">{{email.from.email_address ? getStateAbbreviation(email.from.email_address) : ""}}</span> </v-avatar> </v-list-item-action> </template> <v-list-item-title class="d-flex justify-space-between mb-1"> <div class="d-flex align-center" style="white-space: nowrap; word-break: normal; overflow: hidden; text-overflow: ellipsis;"> {{ email.from.email_address }} </div> <div class="d-none d-md-flex align-center pl-5"> <v-icon v-if="email.has_attachments" icon="mdi-paperclip" size="small"></v-icon> </div> </v-list-item-title> <v-list-item-subtitle class="d-flex justify-space-between"> <div class="d-flex align-center" style="white-space: nowrap; word-break: normal; overflow: hidden; text-overflow: ellipsis;"> {{ email.subject }} </div> <div class="d-none d-md-flex align-center pl-5 text-right" style="min-width:145px"> {{ dayjs(email.received_date).format('MM/DD/YYYY h:mm A') }} </div> </v-list-item-subtitle> <v-list-item-subtitle> <div class="mt-2" v-html="email.body_preview"> </div> </v-list-item-subtitle> </v-list-item> </template> </v-list>
点击事件函数
const loadEmail = async (email : Email) => { if(email.id != currentEmail.value?.id) { selectedEmailLoading.value = true currentEmail.value = await emailStore.getEmail(activeMailboxLabel.value, email.id) // 注释部分是尝试更新选中数组的代码,但时机不对 // selectedEmails.value = selectedEmails.value.map((selectedEmail : Email) => { // if (selectedEmail.id === email.id) { // return currentEmail.value; // } // return selectedEmail; // }); selectedEmailLoading.value = false } }
问题分析
点击列表项时,loadEmail函数会先执行,但v-list的selectedEmails数组更新(把当前邮件加入选中列表)是在点击事件之后的DOM更新周期里,导致注释里的map逻辑执行时,当前邮件可能还没被加入selectedEmails,或者拿的还是旧的数组状态,更新无效。
解决方法
利用Vue的nextTick等待DOM更新完成,确保selectedEmails已经同步选中状态后,再执行替换逻辑:
import { nextTick } from 'vue' const loadEmail = async (email : Email) => { if(email.id != currentEmail.value?.id) { selectedEmailLoading.value = true currentEmail.value = await emailStore.getEmail(activeMailboxLabel.value, email.id) // 等待v-list完成选中状态的更新 await nextTick() // 替换选中数组里对应id的邮件为完整信息版本 selectedEmails.value = selectedEmails.value.map((selectedEmail : Email) => { return selectedEmail.id === email.id ? currentEmail.value : selectedEmail }) selectedEmailLoading.value = false } }
如果需要兼容手动选中的场景,也可以额外判断当前邮件是否在selectedEmails中,不过select-strategy="independent"配置下,v-list会自动处理选中状态,一般不需要额外操作。
内容的提问来源于stack exchange,提问作者Qiuzman
相关产品推荐
相关产品推荐

