如何为嵌套 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",等等
我可以看到一些解决方案,但还没有想出如何让它们中的任何一个起作用:
- 将
:ref="'inputField' + index"
更改为 ref="inputField"
。但是我怎么知道 inputField 正在调用什么来改变它+-1?例如。如何在我的方法中从 inputField2 转到 inputField1?
- 添加一个通用计数器,无论何时添加输入,它都会执行 ++,并使用
:ref="'inputField' + counter"
。但是,每当我尝试通过在 v-for div 之后添加 {{counter++}}
来做到这一点时,我都会得到一个无限循环。
- 还有其他想法吗?
提前致谢!
一种方法是使您的引用规则且可排序,然后在排序的引用列表中找到您当前的位置,以确定哪个是正确的先前引用。
例如,创建一个从索引中计算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:
我有一个 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",等等
我可以看到一些解决方案,但还没有想出如何让它们中的任何一个起作用:
- 将
:ref="'inputField' + index"
更改为ref="inputField"
。但是我怎么知道 inputField 正在调用什么来改变它+-1?例如。如何在我的方法中从 inputField2 转到 inputField1? - 添加一个通用计数器,无论何时添加输入,它都会执行 ++,并使用
:ref="'inputField' + counter"
。但是,每当我尝试通过在 v-for div 之后添加{{counter++}}
来做到这一点时,我都会得到一个无限循环。 - 还有其他想法吗?
提前致谢!
一种方法是使您的引用规则且可排序,然后在排序的引用列表中找到您当前的位置,以确定哪个是正确的先前引用。
例如,创建一个从索引中计算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: