如何在 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">

https://jsfiddle.net/pespantelis/sgsdm6qc/

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/ unshiftreverseArray.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) 方法的调用。