1. 程式人生 > 實用技巧 >Vue.js — 列表渲染

Vue.js — 列表渲染

1.列表渲染

1.1 v-for

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">      
		<style>
			
		</style>
        <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
    </head>
    <body>
        <div id="app">
			<ul>
				<li v-for="item in items" :key="item.id">
					{{item.message}}
				</li>
			</ul>
        </div>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
					items: [
						{id: 1, message: 'Foo'},
						{id: 2, message: 'Bar'}
					]
                }
            });
        </script>
    </body>
</html>

我們可以用v-for指令基於一個數組來渲染一個列表。item in itemsitems是源資料陣列,item是被迭代的陣列元素的別名。
注意:一般情況下,我們會給<li>指定key,這裡的:key表示資料繫結。

v-for支援第二個引數,即當前項的索引。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">      
		<style>
			
		</style>
        <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
    </head>
    <body>
        <div id="app">
			<ul>
				<li v-for="(item, index) in items" :key="index">
					{{item.message}}
				</li>
			</ul>
        </div>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
					items: [
						{id: 1, message: 'Foo'},
						{id: 2, message: 'Bar'}
					]
                }
            });
        </script>
    </body>
</html>

我們可以用v-for指令遍歷一個物件的屬性。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">      
		<style>
			
		</style>
        <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
    </head>
    <body>
        <div id="app">
			<ul>
				<!-- <li v-for="value in object"> -->
				<!-- <li v-for="(value, name) in object"> -->
				<li v-for="(value, name, index) in object" :key="index">
					{{value}}
				</li>
			</ul>
        </div>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
					object: {
						title: 'How to do lists in Vue',
						author: 'Jane Doe',
						publishedAt: '2016-04-10'
					}
                }
            });
        </script>
    </body>
</html>

1.2 陣列更新檢測

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">      
        <style>
            
        </style>
        <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
    </head>
    <body>
        <div id="app">
            <ul>
                <li v-for="(item, index) in items" :key="index">
                    {{item.message}}
					<button @click="updateItem(index, {message: 'Baz'})">更新</button>
					<button @click="deleteItem(index)">刪除</button>
                </li>
            </ul>
			<button @click="addItem({message: 'Boo'})">新增</button>
        </div>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
                    items: [
                        {message: 'Foo'},
                        {message: 'Bar'}
                    ]
                },
				methods: {
					deleteItem: function(index){
						this.items.splice(index, 1)
					},
					updateItem: function(index, newItem){
						this.items.splice(index, 1, newItem)
					},
					addItem: function(newItem){
						this.items.push(newItem)
					}
				}
            });
        </script>
    </body>
</html>

注意:上面的splicepush方法不是陣列原生的方法,而是Vue為了偵聽陣列內部資料而重寫的方法。我們稱這些方法為變異方法(mutation method)
變異方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

相比之下,非變異方法(non-mutating method)不會改變原始陣列,而是返回一個新陣列。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">      
        <style>
            
        </style>
        <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
    </head>
    <body>
        <div id="app">
			<input type="text" v-model="searchName">
            <ul>
                <li v-for="(item, index) in filteritems" :key="index">
                    {{item.message}}
                </li>
            </ul>
        </div>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
					searchName: '',
                    items: [
                        {message: 'Foo'},
                        {message: 'Bar'},
						{message: 'Baz'},
						{message: 'Boo'}
                    ]
                },
				computed: {
					filteritems: function(){
						const {searchName, items} = this
						let arr = [...items]
						if(searchName.trim()){
                            // filter()為非變異方法
							arr = items.filter(item => item.message.toLocaleLowerCase().indexOf(searchName.toLocaleLowerCase())!==-1)
						}
						return arr;
					}
				}
            });
        </script>
    </body>
</html>

1.3 無法檢測的陣列變動

① 利用索引直接設定一個數組項,比如vm.items[indexOfItem] = newValue
② 修改陣列的長度,比如vm.items.length = newLength

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <style>

    </style>
    <!-- <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script> -->
</head>
<body>
<div id="app">
    <ul>
        <li v-for="(item, index) in items" :key="index">
            {{item}}
        </li>
    </ul>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            items: ['a', 'b', 'c']
        }
    });
    vm.items[1] = 'x'
</script>
</body>
</html>

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <style>

    </style>
    <!-- <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script> -->
</head>
<body>
<div id="app">
    <ul>
        <li v-for="(item, index) in items" :key="index">
            {{item}}
        </li>
    </ul>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            items: ['a', 'b', 'c']
        }
    });
    Vue.set(vm.items, 1, 'x')
</script>
</body>
</html>

我們可以使用Vue.set(target, propertyName/index, value)來實現響應式資料。
注意:物件變更檢測注意事項

1.4 在<template>上使用v-for

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">      
        <style>
            
        </style>
        <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
    </head>
    <body>
        <div id="app">
			<ul>
				<template v-for="(item, index) in items" :key="index">
					<li>{{item.name}}</li>
					<li>----------</li>
				</template>				
			</ul>
        </div>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
                    items: [
						{name:'張飛'},
						{name:'李四'},
					]
                }
            });
        </script>
    </body>
</html>

我們可以使用帶有v-for<template>來迴圈渲染一段包含多個元素的內容。

注意:我們不推薦在同一元素上使用v-ifv-for。當它們處於同一節點,v-for的優先順序比v-if更高。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">      
        <style>
            
        </style>
        <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
    </head>
    <body>
        <div id="app">
			<ul v-if="todos.length">
			  <li v-for="todo in todos">
				{{ todo }}
			  </li>
			</ul>
			<p v-else>No todos left!</p>
        </div>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
                    todos: []
                }
            });
        </script>
    </body>
</html>

1.5 在元件上使用v-for

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">      
        <style>
            
        </style>
        <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
    </head>
    <body>
		<div id="todo-list-example">
		  <form v-on:submit.prevent="addNewTodo">
			<label for="new-todo">Add a todo</label>
			<input
			  v-model="newTodoText"
			  id="new-todo"
			  placeholder="E.g. Feed the cat"
			>
			<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"
			  v-on:remove="todos.splice(index, 1)"
			></li>
		  </ul>
		</div>
        <script>
			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: 'Mow the lawn'}
				],
				nextTodoId: 4
			  },
			  methods: {
				addNewTodo: function () {
				  this.todos.push({
					id: this.nextTodoId++,
					title: this.newTodoText
				  })
				  this.newTodoText = ''
				}
			  }
			})
        </script>
    </body>
</html>

任何資料都不會被自動傳遞到元件裡,因為元件有自己獨立的作用域。
為了把迭代資料傳遞到元件裡,我們要使用prop
注意:這裡is="todo-item"實現的效果和<todo-item>相同,但是可以避免一些潛在的瀏覽器解析錯誤。
參考: