如何在 Vue JS 中使用 v-for 和 orderBy 过滤器反转数组的顺序?
How do I reverse the order of an array using v-for and orderBy filter in Vue JS?
我正在使用 Vue JS 进行视图模型绑定。在我的 data
对象中,我有一个按升序排序的项目数组(从旧到新),出于代码原因,我想保持这种方式。
var v = new Vue({
el: '#app',
data: {
items: [
{id: 51, message: 'first'},
{id: 265, message: 'second'},
{id: 32, message: 'third'}
],
}
}
但是,当我在模板中显示数组时,我想颠倒顺序,使其降序(从最新到最旧)。我尝试了以下方法:
<ol>
<li v-for="item in items | orderBy -1" track-by="id">
这没有用,因为 orderBy
过滤器似乎需要一个字段名称作为它的第一个参数。
有没有什么方法可以在模板中使用 v-for
语法并使用 orderBy
过滤器来完成此操作?还是我必须创建自定义 reverse
过滤器?
v-for 指令不支持向后迭代,因此如果您想按最新排序,您将需要添加另一个字段以指示添加项目的时间,或者更改 id
每次添加项目时递增。
然后,field
字段表示添加的顺序:
<li v-for="item in items | orderBy 'field' -1" track-by="id">
Note: The below works in Vue 1, but in Vue 2 filters are deprecated and you
will see: ' Property or method "reverse" is not defined on the
instance but referenced during render.' See tdom_93's answer for
vue2.
您可以创建一个自定义过滤器以 return 倒序的项目:
Vue.filter('reverse', function(value) {
// slice to make a copy of array, then reverse the copy
return value.slice().reverse();
});
然后在v-for
表达式中使用:
<ol>
<li v-for="item in items | reverse" track-by="id">
Vue2 更新
我想展示一些处理数据而不使用过滤器的方法,因为它们在 Vue2 中已弃用:
内部计算属性
使用计算属性代替过滤器,这要好得多,因为您可以在组件中的任何地方使用该数据,而不仅仅是在模板中:
jsFiddle
computed: {
reverseItems() {
return this.items.slice().reverse();
}
}
在 Vuex 内部 getter 属性
如果您使用 Vuex,并且将数据存储在 store.state
对象中。对存储在状态中的数据进行一些转换的最佳方法是在 getters
对象中进行转换( 例如过滤项目列表并计算它们,倒序等...)
getters: {
reverseItems: state => {
return state.items.slice().reverse();
}
}
并从 getters 中的组件计算 属性:
中检索状态
computed: {
showDialogCancelMatch() {
return this.$store.state.reverseItems;
}
}
简洁明了的解决方案:
<li v-for="item in items.slice().reverse()">
//do something with item ...
</li>
对于我的用例(诚然,这显然与 OP 不同......)我想在 v-for 中以相反的顺序 获得数组的索引 "loop."
我的解决方案是创建一个 Vue 应用程序方法 reverseRange(length)
,它 returns 一个从长度 1 到 0 的整数数组。然后我在我的 v-for
指令中使用了它并且简单地每次我需要时都将我的数组元素称为 myArray[index]
。
那样的话,索引的顺序是相反的,然后我就可以使用它们来访问数组的元素。
我希望这能帮助那些像我这样在要求上有细微差别的人登陆此页面。
我没有颠倒创建元素的顺序,而是只改变了显示的顺序。
<ol class="reverseorder">
<li v-for="item in items" track-by="id">
还有我的CSS
<style>
.reverseorder {
display: flex;
flex-direction: column-reverse;
}
</style>
无需克隆数组并反转它。
您可以使用 lodash reverse:
<li v-for="item in _.reverse(items)">
基于指令 v-for
不仅可以接受数组,还可以接受任何其他有效的 JavaScript 可迭代对象 (至少在 Vue 中是这样2.6+ 和 Vue 3 版本),我们可以创建自己的可迭代对象以在相反方向循环遍历所需的数组。我创建了一个非常简化的可运行示例(有关更多详细信息 - 查看有关 JavaScript iterator protocol 的信息)。
class Iterable {
constructor(arr) {
this.arr = arr;
}
*[Symbol.iterator]() {
const arr = this.arr;
for (let i = arr.length - 1; i >= 0; i--) yield arr[i];
}
getIterable(isReversedOrder) {
return isReversedOrder ? this : this.arr;
}
}
Vue.component('list', {
props: ['iterable'],
template: '<ul><li v-for="(el, i) in iterable" :key="`${i}-${el}`">{{ el }}</li></ul>'
});
const app = new Vue({
data() {
return {
todos: new Iterable(['Learn JavaScript', 'Learn Vue', 'Learn Vuex']),
isReversed: true,
inputValue: ''
};
},
computed: {
computedTodos() {
return this.todos.getIterable(this.isReversed);
}
},
methods: {
toggleReverse() {
this.isReversed = !this.isReversed;
},
addTodo() {
this.inputValue && this.todos.arr.push(this.inputValue);
this.inputValue = '';
}
}
});
app.$mount('#app');
<!DOCTYPE html>
<html>
<body style="display: flex; justify-content: center;">
<div id="app">
<button @click="toggleReverse">Toggle reverse to {{ !isReversed }}</button>
<br />
<input v-model="inputValue" style="margin-top:5px;" />
<button @click="addTodo" :disabled="!inputValue">Add todo</button>
<!-- <ul><li v-for="(todo, i) in computedTodos" :key="`${i}-${todo}`">{{ todo }}</li></ul> -->
<list :iterable="computedTodos" />
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script src="script.js"></script>
</body>
</html>
P.S.Try 避免使用诸如 shift
/ unshift
、 reverse
等 Array.prototype
函数从开头添加/删除项目数组或颠倒顺序,特别是在频繁执行此类操作和/或数组包含大量项目的情况下,因为它们在性能方面非常昂贵(具有 O(n) 复杂性)。
另一个好的解决方案是使用 CSS 以相反的顺序显示元素(参见上面的答案)。
可能我在这里遗漏了一些缺点,但是如何使用索引从头到尾遍历数组?
<ol>
<li v-for="i in items.length" :set="item = items[items.length - i]">
例如,如果您的数组包含数千个元素,则每次都使用 .slice().reverse()
复制它可能不是最有效的方法。
更新:注意,:set
是 用于在模板中定义变量,它只是工作。作为替代方案,item
变量可以替换为对封装 items[items.length - i]
表达式的某些 getItem(i)
方法的调用。
我正在使用 Vue JS 进行视图模型绑定。在我的 data
对象中,我有一个按升序排序的项目数组(从旧到新),出于代码原因,我想保持这种方式。
var v = new Vue({
el: '#app',
data: {
items: [
{id: 51, message: 'first'},
{id: 265, message: 'second'},
{id: 32, message: 'third'}
],
}
}
但是,当我在模板中显示数组时,我想颠倒顺序,使其降序(从最新到最旧)。我尝试了以下方法:
<ol>
<li v-for="item in items | orderBy -1" track-by="id">
这没有用,因为 orderBy
过滤器似乎需要一个字段名称作为它的第一个参数。
有没有什么方法可以在模板中使用 v-for
语法并使用 orderBy
过滤器来完成此操作?还是我必须创建自定义 reverse
过滤器?
v-for 指令不支持向后迭代,因此如果您想按最新排序,您将需要添加另一个字段以指示添加项目的时间,或者更改 id
每次添加项目时递增。
然后,field
字段表示添加的顺序:
<li v-for="item in items | orderBy 'field' -1" track-by="id">
Note: The below works in Vue 1, but in Vue 2 filters are deprecated and you will see: ' Property or method "reverse" is not defined on the instance but referenced during render.' See tdom_93's answer for vue2.
您可以创建一个自定义过滤器以 return 倒序的项目:
Vue.filter('reverse', function(value) {
// slice to make a copy of array, then reverse the copy
return value.slice().reverse();
});
然后在v-for
表达式中使用:
<ol>
<li v-for="item in items | reverse" track-by="id">
Vue2 更新
我想展示一些处理数据而不使用过滤器的方法,因为它们在 Vue2 中已弃用:
内部计算属性
使用计算属性代替过滤器,这要好得多,因为您可以在组件中的任何地方使用该数据,而不仅仅是在模板中: jsFiddle
computed: {
reverseItems() {
return this.items.slice().reverse();
}
}
在 Vuex 内部 getter 属性
如果您使用 Vuex,并且将数据存储在 store.state
对象中。对存储在状态中的数据进行一些转换的最佳方法是在 getters
对象中进行转换( 例如过滤项目列表并计算它们,倒序等...)
getters: {
reverseItems: state => {
return state.items.slice().reverse();
}
}
并从 getters 中的组件计算 属性:
中检索状态computed: {
showDialogCancelMatch() {
return this.$store.state.reverseItems;
}
}
简洁明了的解决方案:
<li v-for="item in items.slice().reverse()">
//do something with item ...
</li>
对于我的用例(诚然,这显然与 OP 不同......)我想在 v-for 中以相反的顺序 获得数组的索引 "loop."
我的解决方案是创建一个 Vue 应用程序方法 reverseRange(length)
,它 returns 一个从长度 1 到 0 的整数数组。然后我在我的 v-for
指令中使用了它并且简单地每次我需要时都将我的数组元素称为 myArray[index]
。
那样的话,索引的顺序是相反的,然后我就可以使用它们来访问数组的元素。
我希望这能帮助那些像我这样在要求上有细微差别的人登陆此页面。
我没有颠倒创建元素的顺序,而是只改变了显示的顺序。
<ol class="reverseorder">
<li v-for="item in items" track-by="id">
还有我的CSS
<style>
.reverseorder {
display: flex;
flex-direction: column-reverse;
}
</style>
无需克隆数组并反转它。
您可以使用 lodash reverse:
<li v-for="item in _.reverse(items)">
基于指令 v-for
不仅可以接受数组,还可以接受任何其他有效的 JavaScript 可迭代对象 (至少在 Vue 中是这样2.6+ 和 Vue 3 版本),我们可以创建自己的可迭代对象以在相反方向循环遍历所需的数组。我创建了一个非常简化的可运行示例(有关更多详细信息 - 查看有关 JavaScript iterator protocol 的信息)。
class Iterable {
constructor(arr) {
this.arr = arr;
}
*[Symbol.iterator]() {
const arr = this.arr;
for (let i = arr.length - 1; i >= 0; i--) yield arr[i];
}
getIterable(isReversedOrder) {
return isReversedOrder ? this : this.arr;
}
}
Vue.component('list', {
props: ['iterable'],
template: '<ul><li v-for="(el, i) in iterable" :key="`${i}-${el}`">{{ el }}</li></ul>'
});
const app = new Vue({
data() {
return {
todos: new Iterable(['Learn JavaScript', 'Learn Vue', 'Learn Vuex']),
isReversed: true,
inputValue: ''
};
},
computed: {
computedTodos() {
return this.todos.getIterable(this.isReversed);
}
},
methods: {
toggleReverse() {
this.isReversed = !this.isReversed;
},
addTodo() {
this.inputValue && this.todos.arr.push(this.inputValue);
this.inputValue = '';
}
}
});
app.$mount('#app');
<!DOCTYPE html>
<html>
<body style="display: flex; justify-content: center;">
<div id="app">
<button @click="toggleReverse">Toggle reverse to {{ !isReversed }}</button>
<br />
<input v-model="inputValue" style="margin-top:5px;" />
<button @click="addTodo" :disabled="!inputValue">Add todo</button>
<!-- <ul><li v-for="(todo, i) in computedTodos" :key="`${i}-${todo}`">{{ todo }}</li></ul> -->
<list :iterable="computedTodos" />
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script src="script.js"></script>
</body>
</html>
P.S.Try 避免使用诸如 shift
/ unshift
、 reverse
等 Array.prototype
函数从开头添加/删除项目数组或颠倒顺序,特别是在频繁执行此类操作和/或数组包含大量项目的情况下,因为它们在性能方面非常昂贵(具有 O(n) 复杂性)。
另一个好的解决方案是使用 CSS 以相反的顺序显示元素(参见上面的答案)。
可能我在这里遗漏了一些缺点,但是如何使用索引从头到尾遍历数组?
<ol>
<li v-for="i in items.length" :set="item = items[items.length - i]">
例如,如果您的数组包含数千个元素,则每次都使用 .slice().reverse()
复制它可能不是最有效的方法。
更新:注意,:set
是 item
变量可以替换为对封装 items[items.length - i]
表达式的某些 getItem(i)
方法的调用。