ローカル環境で次のような機能を持ったToDoアプリをVue.jsを使って作成する手順についてまとめています。
実装する機能
- listの追加
- 追加したリストの個々削除
- 空の入力値の場合追加しない
- 完了・未完了のチェックボックス
作業手順
作成までのひとつひとつの流れは以下のようになります。
- Vue.jsの読み込み
- Vueインスタンスの作成
- 空のルートテンプレートの作成
- テンプレートのマウント
- 見出し設置
- フォーム作成
- 入力欄作成
- ボタンの作成
- クリックイベントの設置
- フォームsubmitの無効化(イベント修飾子.prevent)
- inputタグ内容の双方向バインディング
- 追加内容を格納する配列を作成
- 配列にタスクを追加する処理を作成
- タスク追加後にinputタグの表示を消去
- inputタグが空ならタスクを追加しない
- タスクを表示する
- チェックボックスの表示とステータス管理
- リストマークの非表示
- タスク完了時に取消線を設置
- タスク削除機能
Vue.jsの読み込み
<body>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="js/main.js"></script>
</body>
Vue.jsの読み込み
CDNで読み込みます。HTMLファイルを用意して下記のscriptのコードを記載します。
・body終端タグの上に記述。
・真下でjsファイルを読み込む。
<body>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
</body>
Vueインスタンスの作成
.jsファイルを作成して、Vueインスタンスを作成する処理を記述します。
var app = new Vue({
})
空のルートテンプレートの作成
HTMLファイルをVue.js用の空のルートテンプレートファイルにします。
用語は難しいですが、id名がappのdivタグを用意して、上記で作成したjavascriptファイルを読み込むだけです。
<body>
<div id="app">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="js/main.js"></script>
</body>
ルートテンプレートをマウント
上記のHTMLファイルでVue.jsが使えるように、JavaScriptファイルに el: '#app',
を追記します。
var app = new Vue({
el: '#app',
})
以上で、Vue.jsを使うための準備は完了です。
見出し設置
<body>
<div id="app">
<h1>To Do List</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="js/main.js"></script>
</body>
フォーム作成
<body>
<div id="app">
<h1>To Do List</h1>
<!-- ▼追加 -->
<form action="">
</form>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="js/main.js"></script>
</body>
入力欄の作成
<body>
<div id="app">
<h1>To Do List</h1>
<form action="">
<!-- ▼追加 -->
<input type="text" >
</form>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="js/main.js"></script>
</body>
ボタンの作成
<body>
<div id="app">
<h1>To Do List</h1>
<form action="">
<input type="text" >
<!-- ▼追加 -->
<button>追加</button>
</form>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="js/main.js"></script>
</body>
クリックイベントの設置
<body>
<div id="app">
<h1>To Do List</h1>
<form action="">
<input type="text" >
<!-- ▼追加 -->
<button v-on:click="addItem">追加</button>
</form>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="js/main.js"></script>
</body>
var app = new Vue({
el: "#app",
// ▼追加
methods:{
addItem:function(event){
}
}
})
フォームのsubmitを無効化
イベント修飾子 .preventを使って、フォームで次ページのロードを無効にします。
v-on:submit.prevent
<body>
<div id="app">
<h1>To Do List</h1>
<!-- ▼追加 -->
<form v-on:submit.prevent>
<input type="text" >
<button v-on:click="addItem">追加</button>
</form>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="js/main.js"></script>
</body>
inputタグ内容の双方向バインディング
・inputタグの入力内容を保存するdataオプションを作成
・プロパティ名はnewItem
・デバッグ用にdataオプションの中身を表示
var app = new Vue({
el: "#app",
// ▼追加
data:{
newItem:''
},
methods:{
addItem:function(event){
}
}
})
<body>
<div id="app">
<h1>To Do List</h1>
<form v-on:submit.prevent>
<!-- ▼追加 -->
<input type="text" v-model="newItem">
<button v-on:click="addItem">追加</button>
</form>
<pre>{{$data}}</pre>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="js/main.js"></script>
</body>
追加内容を格納する配列を作成
・タスク追加用配列として、tasks[]を用意。
var app = new Vue({
el: "#app",
data:{
newItem:'',
// ▼追加
tasks: []
},
methods:{
addItem:function(event){
}
}
})
配列にタスクを追加する処理を作成
・クリックする毎に、itempプロパティを作成する。
・itemプロパティを配列に格納する。
・イベント修飾子 .push を使用。
var app = new Vue({
el: "#app",
data:{
newItem:'',
tasks: []
},
methods:{
addItem:function(event){
// ▼追加
var task = {
item: this.newItem
};
this.tasks.push(task);
}
}
})
ボタンクリックで {item: this.newItem} を生成。
.pushで、tasks[]の中に追加。
タスク追加後にinputタグの表示を消去
var app = new Vue({
el: "#app",
data:{
newItem:'',
tasks: []
},
methods:{
addItem:function(event){
var task = {
item: this.newItem
};
this.tasks.push(task);
// ▼追加
this.newItem = '';
}
}
})
inputタグが空ならタスクを追加しない
・ifで条件分岐を設定 (※イコールは2つ)
・returnで処理を終了
var app = new Vue({
el: "#app",
data:{
newItem:'',
tasks: []
},
methods:{
addItem:function(event){
// ▼追加
if(this.newItem =='') return;
var task = {
item: this.newItem
};
this.tasks.push(task);
this.newItem = '';
}
}
})
タスクを表示する
・v-for=”変数名 in 配列”
・マスタッシュ構文 {{変数名}}
・変数のプロパティを抜き出す 変数名.プロパティ名
<body>
<div id="app">
<h1>To Do List</h1>
<form v-on:submit.prevent>
<input type="text" v-model="newItem">
<button v-on:click="addItem">追加</button>
</form>
<!-- ▼追加 -->
<li v-for="task in tasks">
<span>{{task.item}}</span>
</li>
<pre>{{$data}}</pre>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="js/main.js"></script>
</body>
チェックボックスの表示とステータス管理
・チェックボックスの初期値をfalse(チェックなし)にする
・inputタグのtype=”checkbox”にv-modelを記述すると、チェックボックスのステータスを双方向バインディングできる
var app = new Vue({
el: "#app",
data:{
newItem:'',
tasks: []
},
methods:{
addItem:function(event){
if(this.newItem =='') return;
var task = {
item: this.newItem,
// ▼追加
isActive: false
};
this.tasks.push(task);
this.newItem = '';
}
}
})
<body>
<div id="app">
<h1>To Do List</h1>
<form v-on:submit.prevent>
<input type="text" v-model="newItem">
<button v-on:click="addItem">追加</button>
</form>
<li v-for="task in tasks">
<!-- ▼追加 -->
<input type="checkbox" v-model="task.check">
<span>{{task.item}}</span>
</li>
<pre>{{$data}}</pre>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="js/main.js"></script>
</body>
リストマークの非表示
・cssで設定
#app li{
list-style: none;
}
※HTMLファイルのheadタグ内でcssファイルを読み込む。<link rel="stylesheet" href="css/main.css">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>To do App</title>
<link rel="stylesheet" href="css/main.css">
</head>
タスク完了時に取消線を設置
・cssのバインディングを使用 v-bind:class{クラス名:真偽値}
┗ trueの時のみ指定したclass属性を付与
<body>
<div id="app">
<h1>To Do List</h1>
<form v-on:submit.prevent>
<input type="text" v-model="newItem">
<button v-on:click="addItem">追加</button>
</form>
<li v-for="task in tasks">
<input type="checkbox" v-model="task.isActive">
<!-- ▼追加 -->
<span v-bind:class="{active:task.isActive}">{{task.item}}</span>
</li>
<pre>{{$data}}</pre>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="js/main.js"></script>
</body>
<span v-bind:class="{active:task.isActive}">{{task.item}}</span>
・spanタグにclass=activeをバインド。
・isActiveの値がtrueなら属性を付与。falseなら付与しない。
CSSファイルを次のように変更します。
#app li{
list-style: none;
}
#app li > span.active{
text-decoration: line-through;
}
タスク削除機能
・削除ボタンの設置
・削除ボタンとインデックス番号を連動
┗ v-for=”(変数1, 変数2) in 配列”
→ 変数2にインデックス番号が入る
・要素の削除 .spliceを使用.splice(開始配列番号, 削除する配列数)
→ array.splice(2,2): 3つ目の要素から2つの要素を削除
var app = new Vue({
el: "#app",
data:{
newItem:'',
tasks: []
},
methods:{
addItem:function(event){
if(this.newItem =='') return;
var task = {
item: this.newItem,
isActive: false
};
this.tasks.push(task);
this.newItem = '';
},
// ▼追加
deleteItem:function(index){
this.tasks.splice(index, 1)
}
}
})
<body>
<div id="app">
<h1>To Do List</h1>
<form v-on:submit.prevent>
<input type="text" v-model="newItem">
<button v-on:click="addItem">追加</button>
</form>
<!-- ▼追加 -->
<li v-for="(task, index) in tasks">
<input type="checkbox" v-model="task.isActive">
<span v-bind:class="{active:task.isActive}">{{task.item}}</span>
<button v-on:click="deleteItem">削除</button>
</li>
<pre>{{$data}}</pre>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="js/main.js"></script>
</body>
完成版のコード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>To do App</title>
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<div id="app">
<h1>To Do List</h1>
<form v-on:submit.prevent>
<input type="text" v-model="newItem">
<button v-on:click="addItem">追加</button>
</form>
<li v-for="(task, index) in tasks">
<input type="checkbox" v-model="task.isActive">
<span v-bind:class="{active:task.isActive}">{{task.item}}</span>
<button v-on:click="deleteItem">削除</button>
</li>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="js/main.js"></script>
</body>
</html>
var app = new Vue({
el: "#app",
data:{
newItem:'',
tasks: []
},
methods:{
addItem:function(event){
if(this.newItem =='') return;
var task = {
item: this.newItem,
isActive: false
};
this.tasks.push(task);
this.newItem = '';
},
deleteItem:function(index){
this.tasks.splice(index, 1)
}
}
})
#app li{
list-style: none;
}
#app li > span.active{
text-decoration: line-through;
}