Vue递归子组件更新/移除的优化方案咨询
Vue递归子组件更新/移除的优化方案咨询
我最近在做一个Vue应用,需要实现类似文件系统的目录结构遍历和展示功能,先给大家看看我目前的实现代码和遇到的问题。
首先是根组件App.vue:
<script setup> import ListItem from './components/ListItem.vue'; const data = { 'C:/': { 'users/': { 'testUser/': { 'documents/': {}, }, }, 'windows/': { 'system32': {}, }, }, 'E:/': { 'test/': {}, }, }; </script> <template> <div style="display: flex; flex-direction: column"> <h1>Recursive Directory Browser</h1> <ListItem title="Browse" :items="data" /> </div> </template> <style scoped></style>
然后是递归使用的ListItem.vue组件:
<script setup> import { defineProps, ref, nextTick } from 'vue'; const props = defineProps({ title: { type: String, required: true, }, items: { type: Object, required: true, }, }); const selectedName = ref(); const selectedValue = ref(); async function updateSelected(key, value) { selectedName.value = key; selectedValue.value = value; } </script> <template> <div style="border: 2px solid black; margin: 1em; padding: .25em;"> <h2>{{ title }}</h2> <div style="display: flex; flex-direction: row;"> <template v-for="(value, key) in items"> <button @click="updateSelected(key, value)">{{ key }}</button> </template> </div> </div> <template v-if="selectedName"> <ListItem :title="selectedName" :items="selectedValue" /> </template> </template> <style scoped></style>
这个实现能正常生成递归的目录浏览器,但有个头疼的bug:当我深入几层目录后,回到父目录选择另一个节点,之前展开的那些子目录组件不会自动消失,就留在界面上了。
我自己临时想了个解决办法,给ListItem加了个updating属性,结合nextTick()来强制刷新,修改后的ListItem.vue代码是这样的:
<script setup> import { defineProps, ref, nextTick } from 'vue'; const props = defineProps({ title: { type: String, required: true, }, items: { type: Object, required: true, }, updating: { type: Boolean, required: false, default: false, }, }); const updating = ref(props.updating); const selectedName = ref(); const selectedValue = ref(); async function updateSelected(key, value) { updating.value = true; await nextTick(); selectedName.value = key; selectedValue.value = value; updating.value = false; } </script> <template> <div style="border: 2px solid black; margin: 1em; padding: .25em;"> <h2>{{ title }}</h2> <div style="display: flex; flex-direction: row;"> <template v-for="(value, key) in items"> <button @click="updateSelected(key, value)">{{ key }}</button> </template> </div> </div> <template v-if="selectedName && !updating"> <ListItem :title="selectedName" :items="selectedValue" :updating="updating" /> </template> </template> <style scoped></style>
虽然这个办法能解决问题,但总觉得有点绕,依赖nextTick()和额外加的属性总不是最优解。想问问大家有没有更优雅的方案,不需要用这些临时手段就能解决这个子组件残留的问题?
备注:内容来源于stack exchange,提问作者Ben Foltz
相关产品推荐
相关产品推荐

