Webアプリを作る機会があり、Vue.jsについて学んだので、今回は簡単なタスク管理アプリを作成しながら、Vue.jsについてまとめてみようと思います。
Vue.jsとは
Vue.jsは、MVVMを採用したJavaScriptのフレームワークです。
双方向データバインディングにより、SPA(シングルページアプリケーション)などのインタラクティブなWebアプリケーションを効率よく開発できるのが特徴です。
アプリケーション向きなので、普通のサイトではVueを使う意味はあまりないかなと、個人的には思います。

仕様を決める
- タイトルと内容を入力でき、送信ボタンでタスクを追加できる
- ドラッグアンドドロップで並び替えできる
- エラー時、タスク追加、タスク削除、並び替えでアラートメッセージ出力
まずは簡単にこの3つの仕様で作っていきます。
必要なもの
HTMLファイルを用意し、headタグ内に次のものを読み込みましょう。
一番上はVue.js本体、Sortable.min.jsとvuedraggable.umd.min.jsはタスクの並び替えに使います。
<script src="//cdn.jsdelivr.net/npm/vue"></script> <!-- ドラッグソート --> <script src="//cdn.jsdelivr.net/npm/sortablejs@1.8.4/Sortable.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/2.20.0/vuedraggable.umd.min.js"></script>
HTML
以下のコードをコピペで大丈夫です。
Vue.jsでは、全体を任意のid(この場合はapp)で囲むのが基本です。
<div id="app">
<div class="app-controller">
<transition name="fade">
<div class="alert alert-success" v-if="success">{{ message }}</div>
<div class="alert alert-failed" v-if="failed">{{ message }}</div>
</transition>
<input type="text" v-model="newTaskName">
<textarea v-model="newTask" cols="30" rows="10"></textarea>
<input type="submit" v-on:click="sendTask(newTask)">
<draggable
element="ul"
v-bind:class="ul"
v-bind:options="{animation:200, delay:50}"
v-bind:list="tasks"
@end="endSort">
<tasklist-box
v-for="(item, index) in tasks"
v-bind:item="item"
v-bind:index="index"></tasklist-box>
</draggable>
</div>
</div>
<transition>
このタグで囲んだ部分はtransitionアニメーションが適用されます。
<draggable>
ドラッグアンドドロップで並び替えする要素をこのタグで囲みます。
デフォルトではdiv要素としてレンダリングされます。
element=”ul”とすることでulタグでレンダリングされます。
v-bind:classにはクラスを、v-bind:optionsにはアニメーションの有無やディレイ(遅延)、
そしていちばん重要なのはv-bind:listです。
これはdataオブジェクト内のどのデータを並び替えるかという指定です。
v-bind:listを指定しなくても見た目上は並び替えができているように見えますが、肝心のdataオブジェクト内のデータが並び替えできないので、必ず指定しましょう。
@endは並び替えが終わった後に実行する処理です。
methodsに定義した関数を実行できます。
JavaScript
こちらもコピペで大丈夫です。
//Vue.js
Vue.component('tasklist-box',{
props: ['item', 'index'],
template: '<li class="tasklist-box"><div class="tasklist-scroll"><p class="itemName">{{ item.name }}</p><p class="itemTxt">{{ item.task }}</p></div><div class="task-close" v-on:click="closeTask(index)"><span></span></div></li>',
methods: {
closeTask: function(index){
app.success=false;
app.failed=false;
app.tasks.splice(index, 1);
app.message='削除しました';
app.success=true;
setTimeout(function(){
app.success=false;
app.failed=false;
app.message='';
},1000);
}
}
});
var app = new Vue({
el: '#app',
data: {
ul: 'tasklist',
newTaskName: '',
newTask: '',
success: false,
failed: false,
message: '',
tasks: []
},
methods: {
endSort: function(){
this.success=false;
this.failed=false;
this.success=true;
this.message='タスクを移動しました';
setTimeout(function(){
app.success=false;
app.failed=false;
app.message='';
},1000);
},
sendTask: function(newTaskName, newTask){
this.success=false;
this.failed=false;
if(this.newTask != ''){
this.tasks.push({name: this.newTaskName, task: this.newTask});
this.newTaskName='';
this.newTask='';
this.message='タスクを追加しました';
this.success=true;
}else{
this.message='入力してください';
this.failed=true;
}
setTimeout(function(){
app.success=false;
app.failed=false;
app.message='';
},1000);
}
}
});
Vue.jsでは、var app = new Vue()の形でインスタンスを作ります。
elには、HTML上で全体を囲っている#appを入れます。
dataはVue内で使う変数の集合体です。
methodsもVue内で使う関数の集まりです。それぞれ、endSort(並び替えが終わった後のアラート表示)、sendTask(送信ボタンを押した時に実行する関数)が定義されています。
Vue.componentは再利用可能なDOM構造(コンポーネント)をテンプレートとして登録します。
注意点として、コンポーネント内からvar appのmethodsは参照することができません。
その場合は、closeTaskのように、コンポーネント側にmethodsを定義します。
CSS
CSSはお好みで調整してください。
body{
margin: 0;
padding: 0;
}
p{
margin: 0;
}
.tasklist{
margin: 0;
list-style: none;
padding: 0;
}
.tasklist-box{
background: #fff;
padding: 20px 10px 10px;
box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.5);
width: 21.6%;
height: 200px;
display: inline-block;
margin:10px;
position: relative;
border-radius: 10px 10px 0 0;
cursor: move;
}
.task-close{
position: absolute;
top: 5px;
right: 5px;
border-radius: 50%;
background: rgb(233, 75, 54);
color: #fff;
font-weight: bold;
text-align: center;
padding: 5px;
cursor: pointer;
}
.task-close span{
background: rgb(104, 32, 22);
display: block;
width: 5px;
height: 5px;
border-radius: 50%;
}
.tasklist-scroll{
overflow-y: scroll;
height: 100%;
}
.app-controller{
padding: 10px;
background: #cccccc;
}
.app-controller textarea{
display: block;
box-sizing: border-box;
width: 100%;
height: 100px;
resize: vertical;
padding: 3px;
margin-bottom: 10px;
}
.app-controller input[type="text"]{
display: block;
padding: 3px;
margin-bottom: 10px;
box-sizing: border-box;
width: 100%;
border: none;
}
.app-controller input[type="submit"]{
color: #fff;
border: #000 1px solid;
font-weight: bold;
background: #000;
padding: 10px;
border: none;
cursor: pointer;
min-width: 100px;
text-align: center;
margin: 0 auto 10px;
display: block;
}
.itemName{
font-weight: bold;
font-size: 20px;
margin-bottom: 5px;
}
.alert{
padding: 10px;
border-radius: 10px;
margin-bottom: 10px;
}
.alert-success{
background: rgb(133, 218, 108);
color: rgb(36, 124, 9);
border: rgb(36, 124, 9) 1px solid;
}
.alert-failed{
background: rgb(233, 75, 54);
color: rgb(104, 32, 22);
border: rgb(104, 32, 22) 1px solid;
}
.fade-enter-active, .fade-leave-active {
transition: .5s;
transform: translate(0, 0);
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
transform: translate(0, -100px);
}
おわりに
最初はVue.jsって何ができるの?データバインディングって何だ?と思っていましたが、実際に学んでみて、データ上の変更をリアルタイムでレンダリングしてくれる、SPAなどのアプリケーション開発に向いているということが分かりました。個人的にはもう少しVue.jsについて勉強してみたいと思いました。また書くかもしれません。
では、また!
