【问题标题】:How can I work around the limitation of multiple root elements in Vue.js? [duplicate]如何解决 Vue.js 中多个根元素的限制? [复制]
【发布时间】:2020-07-04 23:48:21
【问题描述】:

希望这里有人能够帮助我解决这个问题。

我有以下数据:

[
  {
    title: 'Header',
    children: [
      {
        title: 'Paragraph',
        children: [],
      },
    ],
  },
  {
    title: 'Container',
    children: [
      {
        title: 'Paragraph',
        children: [],
      },
    ],
  },
]

我想在<div> 列表中呈现它,如下所示:

<div class="sortable-item" data-depth="1" data-index="0">Header</div> <!-- Parent -->
<div class="sortable-item" data-depth="2" data-index="0">Paragraph</div> <!-- Child-->
<div class="sortable-item" data-depth="1" data-index="1">Container</div> <!-- Parent -->
<div class="sortable-item" data-depth="2" data-index="0">Paragraph</div> <!-- Child-->

我已经构建了一个递归组件,这就是我目前所拥有的:

<template>
  <template v-for="(item, index) in tree">
    <div
      class="sortable-item"
      :data-depth="getDepth()"
      :data-index="index"
      :key="getKey(index)"
    >
      {{ item.title }}
    </div>
    <Multi-Level-Sortable
      :tree="item.children"
      :parent-depth="getDepth()"
      :parent-index="index"
      :key="getKey(index + 0.5)"
    ></Multi-Level-Sortable>
  </template>
</template>

<script>
export default {
  name: 'MultiLevelSortable',
  props: {
    tree: {
      type: Array,
      default() {
        return [];
      },
    },
    parentDepth: {
      type: Number,
    },
    parentIndex: {
      type: Number,
    },
  },
  methods: {
    getDepth() {
      return typeof this.parentDepth !== 'undefined' ? this.parentDepth + 1 : 1;
    },
    getKey(index) {
      return typeof this.parentIndex !== 'undefined' ? `${this.parentIndex}.${index}` : `${index}`;
    },
  },
};
</script>

正如你所见,我不仅有一个 &lt;template&gt; 作为根元素,我还有一个 v-for,Vue.js 的两个“不”。我该如何解决这个问题以呈现我上面指出的元素列表?

注意:我已经尝试过vue-fragment 并且能够实现我想要的结构,但是当我尝试使用Sortable.js 时它不起作用,好像它不会识别任何.sortable-item 元素。

任何帮助将不胜感激!谢谢!

【问题讨论】:

  • 有什么理由不能将元素列表包装在&lt;div&gt; 中吗?顺便说一句,在 Vue 3 中,这个限制正在消失。此外,AFAIK 组件中不能有多个模板标签...
  • @AlexMA 我不想将它们包裹在&lt;div&gt; 中的原因是因为我希望孩子们直接跟随父母等等。让我看看你建议的链接。
  • 那么我很确定在 Vue 3 之前唯一的方法就是使用功能组件。请参阅链接答案。
  • codepen.io/AlgeoMA/pen/bGdmRdQ 如果你想玩它。
  • @AlexMA 感谢您进行快速测试。如果这对我的问题有帮助,我会告诉你的。谢谢!

标签: javascript vue.js


【解决方案1】:

感谢@AlexMA,我能够通过使用功能组件解决我的问题。这是它的样子:

import SortableItemContent from './SortableItemContent.vue';

export default {
  functional: true,
  props: {
    tree: {
      type: Array,
      default() {
        return [];
      },
    },
  },
  render(createElement, { props }) {
    const flat = [];

    function flatten(data, depth) {
      const depthRef = typeof depth !== 'undefined' ? depth + 1 : 0;

      data.forEach((item, index) => {
        const itemCopy = item;

        itemCopy.index = index;
        itemCopy.depth = depthRef;
        itemCopy.indentation = new Array(depthRef);

        flat.push(itemCopy);

        if (item.children.length) {
          flatten(item.children, depthRef);
        }
      });
    }

    flatten(props.tree);

    return flat.map((element) => createElement('div', {
      attrs: {
        'data-index': element.index,
        'data-depth': element.depth,
        class: 'sortable-item',
      },
    },
    [
      createElement(SortableItemContent, {
        props: {
          title: element.title,
          indentation: element.indentation,
        },
      }),
    ]));
  },
};

SortableItemContent 组件如下所示:

<template>
  <div class="item-content">
    <div
      v-for="(item, index) in indentation"
      :key="index"
      class="item-indentation"
    ></div>
    <div class="item-wrapper">
      <div class="item-icon"></div>
      <div class="item-title">{{ title }}</div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'SortableItemContent',
  props: {
    title: String,
    indentation: Array,
  },
};
</script>

鉴于我在我的问题上发布的数据,它现在呈现我想要的 HTML 元素:

<div data-index="0" data-depth="0" class="sortable-item">
  <div class="item-content">
    <div class="item-wrapper">
      <div class="item-icon"></div>
      <div class="item-title">Header</div>
    </div>
  </div>
</div>
<div data-index="0" data-depth="1" class="sortable-item">
  <div class="item-content">
    <div class="item-indentation"></div>
    <div class="item-wrapper">
      <div class="item-icon"></div>
      <div class="item-title">Paragraph</div>
    </div>
  </div>
</div>
<div data-index="1" data-depth="0" class="sortable-item">
  <div class="item-content">
    <div class="item-wrapper">
      <div class="item-icon"></div>
      <div class="item-title">Container</div>
    </div>
  </div>
</div>
<div data-index="0" data-depth="1" class="sortable-item">
  <div class="item-content">
    <div class="item-indentation"></div>
    <div class="item-wrapper">
      <div class="item-icon"></div>
      <div class="item-title">Paragraph</div>
    </div>
  </div>
</div>

再次感谢 @AlexMA 关于功能组件的提示。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-05
    • 1970-01-01
    • 2020-04-10
    • 1970-01-01
    • 2021-02-09
    • 1970-01-01
    • 2021-06-06
    相关资源
    最近更新 更多