学习 Vue.js: Todo 小样组件版
在 上一篇 中写了一个 Todo 小样,但 Vue.js 提供的便利不只有这些,还有组件化。下面将之前的 Todo 小样重写成可重复利用的组件,结果在 codepen.io 上可看到。
注册组件
Vue.js 使用 Vue.component
注册全局组件,下面注册组件 todo-items
。
Vue.component('todo-items', {
template: '#todo-items-template',
props: ['initialTodos'],
data() {
return {
todos: this.initialTodos ? [].concat(this.initialTodos) : [],
newTodo: { title: '', completed: false }
}
},
methods: {
add() {
if (! this.newTodo.title.trim()) { return ; }
this.todos.push({
title: this.newTodo.title,
completed: this.newTodo.completed
});
this.newTodo.title = '';
},
destroy(index) {
this.todos.splice(index, 1);
},
toggleDone(index) {
this.todos[index].completed = !this.todos[index].completed;
},
up(index) {
if (index - 1 < 0) { return ; }
var temp = this.todos[index];
this.todos[index] = this.todos[index-1];
this.todos[index-1] = temp;
this.todos = [].concat(this.todos);
},
down(index) {
if (index + 1 >= this.todos.length) { return ; }
var temp = this.todos[index];
this.todos[index] = this.todos[index+1];
this.todos[index+1] = temp;
this.todos = [].concat(this.todos);
}
}
});
组件中 data
数据是使用函数形式返回的对象,是为了每个组件实例都有独一无二 data 对象。
写模板代码
组件 todo-items
使用的 #todo-items-template
处的模板代码,就是之前的 Todos 的 HTML 代码,用 type="text/x-template
的 script 标签包围。
<script type="text/x-template" id="todo-items-template">
<div class="panel panel-default">
<div class="panel-heading text-center">
计划要做的事情,共 {{ todos.length }} 件
</div>
<div class="panel-body">
<div class="list-groups">
<a class="list-group-item" v-bind:class="{ 'completed': todo.completed }" v-for="(todo, index) in todos">
{{ todo.title }}
<button class="btn btn-xs btn-danger pull-right" v-on:click='destroy(index)'title="删除">✘</button>
<button class="btn btn-xs btn-info pull-right" v-on:click='down(index)'title="下移">↓</button>
<button class="btn btn-xs btn-info pull-right" v-on:click='up(index)'title="上移">↑</button>
<button class="btn btn-xs pull-right" v-on:click='toggleDone(index)' v-bind:class="[todo.completed ? 'btn-success': '']" v-bind:title="[todo.completed ? '点击,标记为未完成': '点击,标记为已完成']">✔</button>
</a>
</div>
</div>
<div class="panel-footer">
<form v-on:submit.prevent="add">
<div class="form-group">
<input type="text" class="form-control text-center" v-model="newTodo.title">
</div>
<button class="btn btn-default btn-block" type="submit">添加</button>
</form>
</div>
</div>
</script>
使用组件
<div id="app" class="container">
<div class="row">
<div class="col-md-6">
<todo-items v-bind:initial-todos="initialTodos"></todo-items>
</div>
<div class="col-md-6">
<todo-items v-bind:initial-todos="initialTodos"></todo-items>
</div>
</div>
</div>
new Vue({
el: '#app',
data: {
initialTodos: [
{title: '吃早饭', completed: false},
{title: '吃午饭', completed: false},
{title: '吃晚饭', completed: false}
]
}
});
注意到,两个组件实例,都赋予了同一个 initialTodos
对象。为了保证每个组件里的 todos
对象是独一无二的,所以组件内部 todos
数据都使用了 [].concat(this.initialTodos)
返回的新数组;否则同一个 Vue 实例下的组件的 todos
数据,会因为引用了同一个对象,行为变一样了。
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: