如何为嵌套 v-for 创建唯一引用?

How to create unique ref for nested v-for?

我有一个 objects 的嵌套数组,像这样:

    taskList: [{
      taskName: "Number One"
    },{
      taskName: "Number Two",
      children: [{
        taskName: "Child One"
      },{
        taskName: "Child due"
      }]
    },{
      taskName: "Number Three"
      }]}

我使用嵌套 v-for 遍历此列表并为每个元素创建一个输入,如下所示:

  <div v-for="(task, index) in taskList">
      <input :ref="'inputField' + index" type="text" v-model="task.taskName" @keydown.up="arrowPress(index, -1)">
      <div v-for="(childOne, childOneIndex) in task.children">
            <input ref="inputField" type="text" v-model="task.taskName" @keydown.up="arrowPress(childOneIndex, -1)">

我设置了一个事件,允许我使用 arrow-keys 通过这些输入 移动焦点 up/down。它的方法如下所示:

      arrowPress(index, value) {
      this.$nextTick(() => this.$refs['inputField'+ (value + index)][0].focus());
      }

这适用于 parent。

但我也希望能够在 children 之间移动。 IE。当我向上按时焦点在 "Number 3" 我想转到 "Child Two" 然后到 "Child One" 然后到 "Number Two",等等

我可以看到一些解决方案,但还没有想出如何让它们中的任何一个起作用:

  1. :ref="'inputField' + index" 更改为 ref="inputField"。但是我怎么知道 inputField 正在调用什么来改变它+-1?例如。如何在我的方法中从 inputField2 转到 inputField1?
  2. 添加一个通用计数器,无论何时添加输入,它都会执行 ++,并使用 :ref="'inputField' + counter"。但是,每当我尝试通过在 v-for div 之后添加 {{counter++}} 来做到这一点时,我都会得到一个无限循环。
  3. 还有其他想法吗?

提前致谢!

一种方法是使您的引用规则且可排序,然后在排序的引用列表中找到您当前的位置,以确定哪个是正确的先前引用。

例如,创建一个从索引中计算ref的方法,这样就不需要重复代码了。在这种情况下,我将 ref 设为 'inputFieldXXXXYYYY',其中 XXXX 是父索引,YYYY 是子索引:

    ref(parent, child) {
        let me = 'inputField' + parent.toString().padStart(4, '0');
        if (child !== undefined) me += child.toString().padStart(4, '0');
        return me;
    },

然后在您的模板中对父项使用 ref(index),对子项使用 ref(index, childIndex):

<div id="main">
    <div v-for="(task, index) in taskList">
        <input :ref="ref(index)" type="text" v-model="task.taskName" @keydown.up="arrowPress(index)">
        <div v-for="(child, childIndex) in task.children">
            <input :ref="ref(index, childIndex)" type="text" v-model="task.taskName" @keydown.up="arrowPress(index, childIndex)">
        </div>
    </div>
</div>

然后在您的 arrowPress 函数中,子项在排序列表中的正确位置找到,您可以递减索引以找到先前的引用:

    arrowPress(parent, child) {
        let refs = Object.keys(this.$refs).filter(key => key.indexOf('inputField') === 0).sort();
        let i = refs.indexOf(this.ref(parent, child));
        i = Math.max(i - 1, 0);
        let prevRef = refs[i];
        this.$nextTick(() => this.$refs[prevRef][0].focus());
    }

这适用于向上箭头键。您可以看到它将如何扩展到向下箭头。

工作fiddle:https://jsfiddle.net/jmbldwn/a1sjk75r/24/

根据评论,这里有一个可能更简单的方法,涉及展平结构,然后在模板中使用单个 v-for:

https://jsfiddle.net/jmbldwn/u0anzm35/7/