代码之家  ›  专栏  ›  技术社区  ›  Ben Foltz

更新/删除递归子组件

  •  0
  • Ben Foltz  · 技术社区  · 5 月前

    我有一个应用程序需要遍历并显示类似于文件系统的目录结构。下面是一个如何使用文件系统的示例。

    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>
    
    

    此代码生成的应用程序如下:

    example directory browser

    问题是,这里有一个错误,用户可以在目录中走几层深,然后如果用户导航回父目录上的不同节点,则已经探索过的路径的子组件仍然存在。

    example directory browser bug result

    我通过添加一个名为的prop/ref来解决这个问题 updating ListItem 组件,并在调用之间切换 nextTick() .

    ListItem.vue使用prop+组件和 nextTick()

    <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>
    
    

    StackBlitz Example

    是否有更好的解决方案不依赖于 nextTick() 以及添加组件+道具?

    1 回复  |  直到 5 月前
        1
  •  2
  •   Estus Flask    5 月前

    updating 旗帜部队 ListItem 在重新分配组件层次结构的数据时重新装载,这是一种解决方法。惯用的方法是使用唯一键,在这种情况下是数据本身:

    <template>
      <div ...>...</div>
      <ListItem
        v-if="selectedName"
        :key="selectedValue"
        :title="selectedName"
        :items="selectedValue"
      />
    </template>