HTML5テクニカルノート
Vue.js + ES6: TodoMVCをつくる 04 ー チェックをまとめてオン/オフしたり削除する
- ID: FN1707002
- Technique: HTML5 / JavaScript
- Library: Vue.js 2.6.10
「Vue.js + ES6: TodoMVCをつくる 03 ー 表示する項目をフィルタで切り替える」(以下「Vue.js + ES6: TodoMVCをつくる 03」)でつくった作例に、項目がまとめて扱える機能をふたつ加えます。ひとつは、終了済みのチェックを、すべての項目にまとめてつけたり消したりするチェックボックスです。もうひとつは、チェック済みの項目をボタンクリックですべてリストから除けるようにします。
01 項目のチェックをまとめてオン/オフする
リストの項目が済んだかどうかのチェックを、まとめてオン/オフできるようにしましょう。チェックボックスの要素<input>
(type
属性"checkbox"
)と<label>
を、つぎのように加え、v-model
ディレクティブに算出プロパティ(allDone
)を与えます。
<body>要素<section class="main" v-show="todos.length" v-cloak> <input id="toggle-all" class="toggle-all" type="checkbox" v-model="allDone"> <label for="toggle-all"></label> </section>
算出プロパティに直に定めた関数は、値を返すgetter関数として扱われます。けれど、オブジェクトにしてメソッドget
とset
を書き加えれば、前者がgetter、後者はsetterになります(「算出 Setter 関数」参照)。つぎのように加えた算出プロパティ(allDone
)は、残り項目(チェックなし)があるかどうかをブール(論理)値で返し、チェックボックスに設定された値(value
)をリスト(todos
)のすべての項目のプロパティ(completed
)に定めます。
script.jsconst app = new Vue({ computed: { allDone: { get() { return this.remaining === 0; }, set(value) { this.todos.forEach((todo) => todo.completed = value ); } } }, });
チェックボックス(class
属性"toggle-all"
)は、CSSでテキスト入力フィールドの左に置かれ、チェック印がつきます(図001)。このオン/オフで項目すべてのチェックがまとめて切り替えられるのです。
図001■上部のチェックボックスですべての項目のチェックがまとめて変えられる
02 チェック済みの項目すべてをリストから除く
チェック済みの項目すべてをリストから除くボタン(<button>
要素)は、つぎのようにフッター(<footer>
要素に加えます。v-on:click
(省略記法@click
)イベントにはメソッド(removeCompleted
)を定めました。また、v-show
ディレクティブは、全リスト項目数より残り(チェックなし)項目数(算出プロパティremaining
)が少ないことを条件にしているので、チェックされている項目がなければ表示されません。
<body>要素<footer class="footer" v-show="todos.length" v-cloak> <button class="clear-completed" @click="removeCompleted" v-show="todos.length > remaining"> Clear completed </button> </footer>
v-on:click
イベントのリスナーメソッド(removeCompleted()
)はつぎのように定めます。フィルタ(filters
)のメソッド(active()
)で、チェックのない項目の配列を得て、項目リストのプロパティ(todos
)に上書きします。これで、リストからチェック済みの項目がなくなるわけです。
script.jsconst app = new Vue({ methods: { removeCompleted() { this.todos = filters.active(this.todos); } } });
これで、チェック済みの項目をボタンクリックでまとめてリストから除けるようになりました(図002)。すべての項目にチェックをつけたり消したりするチェックボックスと合わせて、ふたつの機能が備わったのです。以下のコード001に、<body>
要素とJavaScriptファイルの記述をまとめました。サンプル001にはCodePenのコードを掲げてあります。
図002■チェックした項目がまとめて除かれる
コード001■リストに表示される項目がフィルタで切り替わる
<body>要素
<section class="todoapp">
<header class="header">
<h1>todos</h1>
<input class="new-todo"
autofocus
autocomplete="off"
placeholder="What needs to be done?"
v-model="newTodo"
@keypress.enter="addTodo">
</header>
<section class="main" v-show="todos.length" v-cloak>
<input id="toggle-all" class="toggle-all" type="checkbox" v-model="allDone">
<label for="toggle-all"></label>
<ul class="todo-list">
<li v-for="todo in filteredTodos"
class="todo"
:key="todo.id"
:class="{completed: todo.completed}">
<div class="view">
<input class="toggle" type="checkbox" v-model="todo.completed">
<label>{{todo.title}}</label>
<button class="destroy" @click="removeTodo(todo)"></button>
</div>
</li>
</ul>
</section>
<footer class="footer" v-show="todos.length" v-cloak>
<span class="todo-count">
<strong>{{remaining}}</strong> {{remaining | pluralize}} left
</span>
<ul class="filters">
<li><a href="#/all" :class="{selected: visibility == 'all'}">All</a></li>
<li><a href="#/active" :class="{selected: visibility == 'active'}">Active</a></li>
<li><a href="#/completed" :class="{selected: visibility == 'completed'}">Completed</a></li>
</ul>
<button class="clear-completed" @click="removeCompleted" v-show="todos.length > remaining">
Clear completed
</button>
</footer>
</section>
const STORAGE_KEY = 'todos-vuejs-2.0';
const todoStorage = {
fetch() {
const todos = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
todos.forEach((todo, index) =>
todo.id = index
);
todoStorage.uid = todos.length;
return todos;
},
save(todos) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(todos));
}
};
const filters = {
all(todos) {
return todos;
},
active(todos) {
return todos.filter((todo) =>
!todo.completed
);
},
completed(todos) {
return todos.filter((todo) =>
todo.completed
);
}
};
const app = new Vue({
data: {
todos: todoStorage.fetch(),
newTodo: '',
visibility: 'all'
},
watch: {
todos: {
handler(todos) {
todoStorage.save(todos);
},
deep: true
}
},
computed: {
filteredTodos() {
return filters[this.visibility](this.todos);
},
remaining() {
const todos = filters.active(this.todos);
return todos.length;
},
allDone: {
get() {
return this.remaining === 0;
},
set(value) {
this.todos.forEach((todo) =>
todo.completed = value
);
}
}
},
filters: {
pluralize(n) {
return n === 1 ? 'item' : 'items';
}
},
methods: {
addTodo() {
const value = this.newTodo && this.newTodo.trim();
if (!value) {
return;
}
this.todos.push({
id: todoStorage.uid++,
title: value,
completed: false
});
this.newTodo = '';
},
removeTodo(todo) {
this.todos.splice(this.todos.indexOf(todo), 1);
},
removeCompleted() {
this.todos = filters.active(this.todos);
}
}
});
function onHashChange() {
const visibility = window.location.hash.replace(/#\/?/, '');
if (filters[visibility]) {
app.visibility = visibility;
} else {
window.location.hash = '';
app.visibility = 'all';
}
}
window.addEventListener('hashchange', onHashChange);
onHashChange();
app.$mount('.todoapp');
サンプル001■Vue.js + ES6: Vue TodoMVC 04
See the Pen Vue.js + ES6: Vue TodoMVC 04 by Fumio Nonaka (@FumioNonaka) on CodePen.
- Vue.js + ES6: TodoMVCをつくる 01 ー 項目の追加と削除および残り項目数表示
- Vue.js + ES6: TodoMVCをつくる 02 ー データをローカルに保存する
- Vue.js + ES6: TodoMVCをつくる 03 ー 表示する項目をフィルタで切り替える
- Vue.js + ES6: TodoMVCをつくる 04 ー チェックをまとめてオン/オフしたり削除する
- Vue.js + ES6: TodoMVCをつくる 05 ー 項目のテキストを再編集できるようにする
作成者: 野中文雄
更新日: 2019年11月14日 構文をECMAScript 2015に改め、本文も修正。サンプルはCodePenに差し替えた。
作成日: 2017年07月05日
Copyright © 2001-2019 Fumio Nonaka. All rights reserved.