Vue基础篇--5列表渲染v-for

Posted xujunkai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue基础篇--5列表渲染v-for相关的知识,希望对你有一定的参考价值。

Vue基础篇--5列表渲染v-for

1.用v-for把一个数组对弈为一组元素

  • 我们用v-for指令根据一组数组选项列表进行渲染。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<script src="./vue.js"></script>
<body>
    <ul id="exp1">
        <li v-for="item in items">
            {{item.message}}
        </li>
    </ul>
</body>
<script>
    var vm =new Vue({
        el:"#exp1",
        data:{
            items:[
                {message:"Foo"},
                {message:"Bar"},
            ]
        }
    })
</script>
</html>
  • 当然v-for中,我们可以访问父作用域属性
<ul id="exp2">
        <li v-for="(item,index) in items">
            {{parentMsg}}-{{item.message}}-{{index}}
        </li>
</ul>
    var vm =new Vue({
        el:"#exp2",
        data:{
            parentMsg:"parent",
            items:[
                {message:"Foo"},
                {message:"Bar"},
                {message:"Der"},
            ]
        }
    })
  • 也可以用of代替in做为分隔符,因为它是接近javascript迭代器的语法:
<div v-for="item of items"></div>

2.一个对象v-for

  • 你也可以用v-for通过一个对象的属性来迭代
<ul id="exp1">
    <li v-for="value in object">
        {{value}}
    </li>
</ul>
var vm = new Vue({
    el:"#exp1",
    data:{
        object:{
            firstName:"Xu",
            lastName:"Junkai",
            age:20
        }
    }
})
  • 可以提供2个参数:键、值
<ul id="exp1">
        <li v-for="(value,key) in object">
            {{key}}:{{value}}
        </li>
    </ul>
  • 提供三个参数:键、值、索引
<ul id="exp1">
    <li v-for="(value,key,index) in object">
    {{index}}-{{key}}:{{value}}
    </li>
</ul>

3.key

  • 当Vue.js用v-for更新已渲染元素列表时,它默认用就地复用策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素 ,并且确保它在特定索引下显示已被渲染过的每个元素。

    这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态

    为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。理想的 key 值是每项都有的唯一 id。这个特殊的属性相当于 Vue 1.x 的 track-by ,但它的工作方式类似于一个属性,所以你需要用 v-bind 来绑定动态值 (在这里使用简写):

    <div v-for="item in items" :key="item.id">
      <!-- 内容 -->
    </div>

    建议尽可能在使用 v-for 时提供 key,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。

    因为它是 Vue 识别节点的一个通用机制,key 并不与 v-for 特别关联,key 还具有其他用途,我们将在后面的指南中看到其他用途。

4.数组更新检测

变异方法

  • Vue包含一组观察数组变异方法, 所以它们也将会触发视图更新。这些方法如下:

    push()
    pop()
    shift()
    unshift()
    splice()
    sort()
    reverse()
  • 控制台输入:

    vm.items.push({message:"Dem"})

替换数组

  • 变异方法顾名思义,会改变被这些方法调用的原始数组。相比也有非编译方法,如:filter(),concat()slice(),这些不会改变原始数组,但 总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组:
var vm =new Vue({
        el:"#exp2",
        data:{
            parentMsg:"parent",
            items:[
                {message:"Foo"},
                {message:"Foo"},
                {message:"Der"},
            ]
        }
    });
    var tm = vm.items.filter(function (item) {
        return item.message.match(/Foo/)
    });

你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是,事实并非如此。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的、启发式的方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。

注意事项

  • 由于JavaScript的限制,Vue不能检测以下变动的数组:

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

        <ul id="exp">
            <li v-for="item in items">
                {{item}}
            </li>
        </ul>
    var vm = new Vue({
        el:"#exp",
        data:{
            items:['a','b','c']
        }
    });
    vm.items[1] = "X";//不是响应性的
    vm.items.length = 2;//不是响应性的
  • 为解决第一类问题,通过以下2种方式可以实现和 vm.items[indexOfItem] = newValue 相同的效果,同时也将触发状态更新:

    //1. Vue.set
    Vue.set(vm.items, indexOfItem, newValue)
    e.g.:
    Vue.set(vm.items,1,"x");
    
    //2. Array.prototype.splice
    vm.items.splice(indexOfItem, 1, newValue)
    e.g.:
    //替换起始下标为1,长度为1的值为“xxx”
        vm.items.splice(1,1,"xxx");
  • 也可以使用vm.$set实例方法

    e.g.:
      vm.$set(vm.items,1,"x");
  • 第二类问题,可以使用splice:

    vm.items.splice(newLength)
    • 注意:目前splice只能把数组变小

5.对象更改检测注意事项

  • 由于JavaScript的限制,Vue不能检测对象属性的添加或删除。

    var vm = new Vue({
        data:{
            a:1
        }
    });
    // vm.a 响应式的
    // vm.b = 2 不是响应式的
  • 对于已经创建的实例,Vue 不能动态添加根级别的响应式属性。但是,可以使用 Vue.set(object, key, value) 方法向嵌套对象添加响应式属性。例如,对于:

<ul id="exp">
    <li v-for="value in userProfile">
        {{value}}
    </li>
</ul>
var vm = new Vue({
    el:"#exp",
    data:{
        userProfile:{
            name:"Anika",
        }
    }
});
Vue.set(vm.userProfile,"age",27)
  • 你还可以使用 vm.$set 实例方法,它只是全局 Vue.set 的别名:
// 比如在Console输入
vm.$set(vm.userProfile,"addr","beijing")
  • 有时你可能需要为已有对象赋予多个新属性,比如使用 Object.assign()_.extend()。在这种情况下,你应该用两个对象的属性创建一个新的对象。所以,如果你想添加新的响应式属性,不要像这样:
Object.assign(vm.userProfile,{hobby:'sleep',gender:'male'})
//没有响应变化
  • 而是应该这样
vm.userProfile = Object.assign({},vm.userProfile,{hobby:'sleep',gender:'male'})

6.显示过滤、排序结果

  • 有时,我们想要显示一个数组的过滤或排序副本,而不实际改变或重置原始数据。在这种情况下,可以创建返回过滤或排序数组的计算属性。
<ul id="exp">
    <li v-for="n in evenNumbers">
        {{n}}
    </li>
</ul>
// 筛选 除2 余数 为0
var vm = new Vue({
    el:"#exp",
    data:{
        numbers:[1,2,3,4,5]
    },
    computed:{
        evenNumbers:function () {
            return this.numbers.filter(function(number){
                return number % 2 === 0
            })
        }
    }
})
  • 在计算属性不适用的情况下 (例如,在嵌套 v-for 循环中) 你可以使用一个 method 方法:
data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
methods: {
  even: function (numbers) {
    return numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

7.一段取值范围的v-for

  • v-for 也可以取整数。在这种情况下,它将重复多次模板。
<div id="exp">
    <span v-for="n in 10">{{n}}</span>
</div>
new Vue({
    el:"#exp"
})

8.v-for on a <template>

  • 类似于 v-if,你也可以利用带有 v-for 的 ` 渲染多个元素。比如:
<ul id="exp">
    <template v-for="item in items">
        <li>{{item.msg}}</li>
        <li class="divier" role="presentation"></li>
    </template>
</ul>
new Vue({
    el:"#exp",
    data:{
        items:[
            {msg:"one"},
            {msg:"two"},
            {msg:"three"},
        ]
    }
})

9.v-for with v-if

  • 当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。当你想为仅有的一些项渲染节点时,这种优先级的机制会十分有用,如下:
<ul id="exp">
    <li v-for="todo in todos" v-if="!todo.isComplete">
        {{todo.msg}}
    </li>
</ul>
new Vue({
    el:"#exp",
    data:{
        todos:[
            {isComplete:true,msg:1},
            {isComplete:false,msg:2},
            {isComplete:true,msg:3},
        ]
    }
})
  • 而如果你的目的是有条件地跳过循环的执行,那么可以将 v-if 置于外层元素 (或 <template>)上。如:
<div id="exp2">
    <ul v-if="todos.length">
        <li v-for="todo in todos">{{todo}}</li>
    </ul>
    <p v-else>No todos left!</p>
</div>
new Vue({
    el:"#exp2",
    data:{
        todos:[1,2,3]
    }
});

10.一个组件的v-for

  • 任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了把迭代数据传递到组件里,我们要用 props
<my-component
  v-for="(item, index) in items"
  v-bind:item="item"
  v-bind:index="index"
  v-bind:key="item.id"
></my-component>
  • 不自动将 item 注入到组件里的原因是,这会使得组件与 v-for 的运作紧密耦合。明确组件数据的来源能够使组件在其他场合重复使用。
<div id="todo-list-example">
    <!-- 提交事件不再重载页面 -->
    <form v-on:submit.prevent="addNewTodo">
        <label for="new-todo">Add a todo</label>
        <input type="text" v-model="newTodoText" id="new-todo" placeholder="E.g.">
        <button>Add</button>
    </form>
    <ul>

        <li is="todo-item" v-for="(todo,index) in todos"
            v-bind:key="todo.id"
            v-bind:title="todo.title"
            <!-- 这里定义remove事件 -->
            v-on:remove="todos.splice(index,1)"></li>
    </ul>
</div>
// props 用来接收父组件传递给子组件的数据。
//  子组件通过$emit 触发父组件remove事件。
Vue.component('todo-item',{
    template:`
    <li>
        {{ title }}
        <button v-on:click="$emit('remove')">Remove</button>
    </li>`,
    props:['title']
});
new Vue({
    el:"#todo-list-example",
    data:{
        newTodoText:"",
        todos:[
            { id:1,title:"Do the dishes"},
            { id:2,title:"Take out the trash"},
            { id:3,title:"Now the lawn"},
        ],
        nextTodoId:4
    },
    methods:{
        addNewTodo:function () {
            console.log(this);
            this.todos.push({
                id:this.nextTodoId++,
                title:this.newTodoText
            });
            this.newTodoText = ''
        }
    }
})
  • 注意这里的 is="todo-item" 属性。这种做法在使用 DOM 模板时是十分必要的,因为在 元素内只有 元素会被看作有效内容。这样做实现的效果与 `` 相同,但是可以避开一些潜在的浏览器解析错误。查看 DOM 模板解析说明 来了解更多信息。

参照文献:Vue.js列表渲染

以上是关于Vue基础篇--5列表渲染v-for的主要内容,如果未能解决你的问题,请参考以下文章

Vue.2.0.5-列表渲染

Vue-Vue列表渲染v-for

Vue学习计划(基础三)-class与style绑定,条件渲染和列表渲染

vue2.0 之列表渲染-v-for

Vue—列表渲染v-for指令

VUE指令-列表渲染v-for