前面的话

Vue 的核心是数据与视图的双向绑定,当我们修改数组时,Vue会检测到数据变化,所以用v-for 渲染的视图也会立即更新。Vue为了增加列表渲染的功能,增加了一组观察数组的方法,而且可以显示一个数组的过滤或排序的副本。这篇文章将介绍Vue数组更新及过滤排序。

变异方法

Vue包含了一组观察数组变异的方法,使用它们改变数组也会触发视图更新。
● push() 接受任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。

● pop() 从数组末尾移除最后一项,减少数组的length值,然后返回移除的项

● shift() 移除数组中的第一个项并返回该项,同时数组的长度减1

● unshift() 在数组前端添加任意一个项并返回新数组长度

● splice() 删除原数组的一部分成员,并可以在被删除的位置添加新的数组成员

● sort() 调用每个数组的toString()方法,然后比较得到的字符串排序,返回经过排序之后的数组。

● reverse() 用于反转数组的顺序,返回经过排序之后的数组

 <div id="app1">
         <div>
             <button @click="push">push</button>
             <button @click="pop">pop</button>
             <button @click="shift">shift</button>
             <button @click="unshift">unshift</button>
             <button @click="splice">splice</button>
             <button @click="sort">sort</button>
             <button @click="reverse">reverse</button>
         </div>
         <ul>
             <li v-for="item in items">
                 {{ item.message}}
             </li>
         </ul>
     </div>
<script>
	  new Vue({
        el: "#app1",
        data: {
            items: [
                {message: 'FOO'},
                {message: "Bar"},
                {message: "Baz"}
            ],
            addValue: {message: 'match'}
        },
        methods: {
            push() {
                this.items.push(this.addValue);
            },
            pop() {
                this.items.pop();
            },
            shift() {
                this.items.shift();
            },
            unshift() {
                this.items.unshift(this.addValue);
            },
            splice() {
                this.items.splice(0,1);
            },
            sort() {
                this.items.sort();
            },
            reverse() {
                this.items.reverse();
            }
        }
    })
</script>

在这里插入图片描述

非变异方法

使用以上方法会改变调用这些方法调用的原始数组,但有些方法不会改变原数组。

● concat() 先创建当前数组的副本,然后将接受到的参数添加到这个副本的末尾,最后返回新构建的数组

● slice() 基于当前数组中一个或多个项创建一个新数组,接受一个或两个参数,即要返回项的起始和结束位置 最后返回新数组。

● map() 对数组的每一项运行给定的函数,返回每次函数调用的结果组成的数组

● filter() 对数组中的每一项运行给定函数,该函数会返回true的项组成的数组

  <div id="app2">
         <div>
             <button @click="concat">concat</button>
             <button @click="slice">slice</button>
             <button @click="map">map</button>
             <button @click="filter">filter</button>
         </div>
         <ul>
             <li v-for="item in items ">
                 {{item}}
             </li>
         </ul>
     </div>
    <script>
     new Vue({
        el: "#app2",
        data: {
            items:[
                "foo",
                "Bar",
                "Baz"
            ],
            addValue: "match"
        },
        methods: {
            concat() {
                this.items = this.items.concat(this.addValue);
            },
            slice() {
                this.items = this.items.slice(1);
            },
            map() {
                this.items = this.items.map(function(item,index,arr) {
                    return index + item;
                });
            },
            filter() {
                this.items = this.items.filter(function(item,index,arr) {
                    return (index > 0);
                });
            }
        }
    })     
    </script> 

在这里插入图片描述
Vue在检测到数组变化时,并不是直接重新渲染整个列表,而是最大化地复用DOM元素。替换的数组中, 含有相同元素的项不会被重新渲染,因此可以大胆地用新数组来替换旧数组,不用担心性能问题。

无法检测

由于js的限制,Vue不能检测以下变动的数组,视图也不会更新:

1: 利用索引直接设置一个项时,例如: vm.items[indexOfItem] = newValue
2: 修改数组的长度时,例如:vm.items.length = newLength

 <div id="app3">
         <div>
             <button @click='setVal'>setVal</button>
             <button @click='setLength'>setLength</button>
             <button @click='pop'>pop</button>
         </div>
         <ul>
             <li v-for="item in items">{{ item }}</li>
         </ul>
         <p>{{ message}}</p>
     </div>
     <script>
     	     
   var vm =  new Vue({
        el: '#app3',
        data: {
            items: ["foo","Bar","Baz"],
            message: ''
        },
        watch: {
            items:  watchFunc = function() {
                        this.message = '数据发生变化';
                        var that = this;
                        setTimeout(function() {
                            that.message = '';
                            },500);
                        }
        },
        methods: {
            pop() {
                this.items.pop();
            },
            setVal() {
                this.items[0] = 'match';
            },
            setLength() {
                this.items.length = 2;
            }
        }
    })
     </script>

在这里插入图片描述

可以看到点击前面两个按钮没有变化,即直接设置值和长度watch不能监听到其变化

如何解决这两个问题?

有两种方法都可以实现vm.items[indexOfItem] = newValue相同的效果,同时也触发状态更新。

1: 使用Vue内置的方法set
Vue.set(vm.items, indexOfItem, newValue)

2:使用splice方法
vm.items.splice(indexOfItem, 1 ,newValue)

解决第二类问题,也可以直接使用splice
vm.items.splice(newLength)

 <div id="app4">
         <div>
             <button @click='setVal1'>setVal1</button>
             <button @click='setVal2'>setVal1</button>
             <button @click='setLength'>setLength</button>
         </div>
         <ul>
             <li v-for="item in items">
                 {{ item }}
             </li>
         </ul>
         <p>{{message}}</p>
     </div>
 <script>
     	 new Vue({
         el: "#app4",
         data: {
             items: ['Foo','Bar', 'Baz'],
             message: ''
         },
         watch: {
             items: watchFunc = function(){
                this.message = "数据发生变化";
                var that = this;
                setTimeout(function() {
                    that.message = '';
                },500);
             }
         },
         methods: {
             setVal1() {
                 Vue.set(this.items, 0, 'match');
             },
             setVal2() {
                 this.items.splice(1, 1, 'xiaoqi');
              },
              setLength() {
                  this.items.splice(2);
                //   删除第三个元素
              }
         }
    })
</script>

在这里插入图片描述
过滤与排序

当你不想改变原数组,想通过一个数组的副本来做过滤或排序的显示时,可以使用计算属性来返回 过滤或排序后的数组。

实例1:

<div id="app5">
        <ul>
            <li v-for="n in Numbers">
                {{n}}
            </li>
        </ul>
 </div>
 <script>
  new Vue({
        el: '#app5',
        data: {
            numbers: [ 1, 2, 3, 4, 5 ],
        },
        computed: {
            Numbers: function() {
                return this.numbers.filter(function (item) {
                    return item % 2 === 0;
                })
            }
        }
    })
</scripit>

上例中把是2的倍数的数据过滤出来,计算属性Numbers依赖numbers,但是不会修改numbers
在这里插入图片描述

实例2:

<div id="app6">
        <ul>
            <template v-for="book in filterBooks">
                <li>书名: {{ book.name }}</li>
                <li>作者: {{ book.author }}</li>
            </template>
        </ul>
    </div>
    <script>
     new Vue({
        el: "#app6",
        data: {
            books: [
                { 
                    name: '<< JavaScript高级程序设计>>',
                    author: 'Nicholas'
                },
                {
                    name: '<< JavaScript语言精粹>>',
                    author: 'Douglas Crockford'
                },
                {
                    name: "<< 深入理解ES6>>",
                    author: '阮一峰'
                }
            ]
        },
        computed: {
            filterBooks: function() {
                return this.books.filter(function (item) {
                    return item.name.match(/JavaScript/);
                })
            },
        }
    })
    </script>

在这里插入图片描述
上例中把书名中包含JavaScript 的数据过滤出来,计算属性filterBooks依赖 books,但是不会修改 books.

Logo

前往低代码交流专区

更多推荐