【问题标题】:How do I reverse the order of an array using v-for and orderBy filter in Vue JS?如何在 Vue JS 中使用 v-for 和 orderBy 过滤器反转数组的顺序?
【发布时间】:2016-10-04 22:03:51
【问题描述】:

我正在使用 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 过滤器?

【问题讨论】:

    标签: javascript arrays vue.js


    【解决方案1】:

    简单简洁的解决方案:

    <li v-for="item in items.slice().reverse()">
    //do something with item ...
    </li>
    

    【讨论】:

    • 这是正确答案。人为什么要把事情搞得这么复杂?修辞。
    • 虽然这是答案的一种解决方案,但我想说您必须从提供解决方案的开发人员的角度来看。许多经验丰富的开发人员努力将业务逻辑和显示逻辑分开。尤其是那些处理过将两者合并在一起的痛点的人。该解决方案有效,是的,它是一个很好的替代方案或附加解决方案。然而,它确实将业务逻辑与显示逻辑混合在一起,超出了大多数人认为可接受的范围。
    • @RyanWatts 这就是使用.slice() 方法的原因。它会返回一个新的数组,所以原来的items数组不会受到影响。
    • 它可以工作,但在我的控制台中返回一个错误 slice 不是函数
    • 这不是非常低效吗?您创建数组的副本,而不是仅从最后一个索引而不是第一个索引对其进行迭代...
    【解决方案2】:

    注意: 以下内容在 Vue 1 中有效,但在 Vue 2 中过滤器已被弃用,您 将看到:' 属性或方法“reverse”未定义在 实例,但在渲染期间被引用。请参阅 tdom_93 的 答案 vue2.

    您可以创建一个自定义过滤器以相反的顺序返回项目:

    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/

    【讨论】:

    • Not working in vue 2.0,error is ' 属性或方法“reverse”未在实例上定义,但在渲染期间被引用。'
    【解决方案3】:

    Vue2 更新

    我想展示一些可以处理数据而不是使用过滤器的方法,因为它们在 Vue2 中不推荐使用

    计算属性内部

    使用计算属性代替过滤器,这会更好,因为您可以在组件中的任何地方使用该数据,而不仅仅是在模板中: jsFiddle

    computed: {
        reverseItems() {
            return this.items.slice().reverse();
      }     
    }
    

    Vuex getter 属性内部

    如果您使用的是 Vuex,并且您将数据存储在 store.state 对象中。对存储在状态中的数据进行一些转换的最佳方法是在 getters 对象中进行(例如过滤项目列表并计算它们,逆序等等......)

    getters: {
        reverseItems: state => {
            return state.items.slice().reverse();
        }
    }
    

    并从组件计算属性中的 getter 中检索状态:

    computed: {
        showDialogCancelMatch() {
            return this.$store.state.reverseItems;
        }
    }
    

    【讨论】:

    • 有一个错误,第二个sn-p应该是:return store.getters.reverseItems
    • 这会创建一个计算数组,它很好并且可以工作,但是当您从原始数据源中删除项目时,索引键是不同的。有什么方法可以保持密钥不变,所以删除不是问题?
    【解决方案4】:

    我没有颠倒创建元素的顺序,只是改变了显示的顺序。

    <ol class="reverseorder">
        <li v-for="item in items" track-by="id">
    

    还有我的 CSS

    <style>
    .reverseorder {
      display: flex;
      flex-direction: column-reverse;
    }
    </style>
    

    无需克隆数组并反转它。

    【讨论】:

    • 这是目前最理想的答案。在 Javascript 数组中进行反向操作是另一种处理
    • 哇!这是绝妙的解决方案。轻巧且非常灵活)谢谢
    • 作为旁注,这不会反转标签索引 - 这意味着标签顺序将是错误的。这不利于可访问性,因此如果您使用交互式元素(例如输入),请记住这一点。
    • 我喜欢什么很棒的解决方案,非常感谢。
    【解决方案5】:

    v-for 指令不支持向后迭代,因此如果您想按最新排序,则需要添加另一个字段来指示添加项目的时间,或者将 id 更改为每次递增添加了一个项目。

    然后,field 是指示添加顺序的字段:

    <li v-for="item in items | orderBy 'field' -1" track-by="id">
    

    【讨论】:

      【解决方案6】:

      对于我的用例(诚然,这显然不同于 OP...),我希望在 v-for“循环”中具有数组的索引以相反的顺序

      我的解决方案是创建一个 Vue 应用程序方法 reverseRange(length),它返回一个从长度为 1 到 0 的整数数组。然后我在我的 v-for 指令中使用它,并将我的数组元素简单地称为 myArray[index] every我需要它的时间。

      这样,索引是相反的顺序,然后我可以使用它们来访问数组的元素。

      我希望这可以帮助那些像我一样在要求中有细微差别的人登陆此页面。

      【讨论】:

        【解决方案7】:

        你可以使用lodash reverse:

        <li v-for="item in _.reverse(items)">
        

        【讨论】:

          【解决方案8】:

          基于指令 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>

          PS尽量避免使用shift/unshiftreverseArray.prototype函数从数组的开头添加/删除项目或颠倒顺序,特别是在这种操作的情况下经常执行和/或数组包含大量项目,因为它们在性能方面非常昂贵(具有 O(n) 复杂性)。 另一个好的解决方案是使用 CSS 以相反的顺序显示元素(参见上面的答案)。

          【讨论】:

            【解决方案9】:

            可能我在这里遗漏了一些缺点,但是如何使用索引从头到尾遍历数组?

            <ol>
              <li v-for="i in items.length" :set="item = items[items.length - i]">
            

            例如,如果您的数组包含数千个元素,则每次使用 .slice().reverse() 复制它可能不是最有效的方法。

            更新:注意,:setnot an official way 用于在模板中定义变量,它可以正常工作。作为替代方案,item 变量可以替换为对封装items[items.length - i] 表达式的某个getItem(i) 方法的调用。

            【讨论】:

              猜你喜欢
              • 2020-05-15
              • 2020-03-29
              • 1970-01-01
              • 2020-07-01
              • 2019-12-16
              • 1970-01-01
              • 2019-04-29
              • 2020-05-06
              • 2018-09-16
              相关资源
              最近更新 更多