前提・実現したいこと
Vue.jsで簡単なToDoListを作成しました。機能ごとにコンポーネントを切り出していったのですが、そもそもこういったやり方が正しいのかがわからず、単一コンポーネントで処理したほうが見読性も高いような気がします。
特に気になっている下記についてご教示頂きたいです。
- Vue.jsの特性を無視した書き方をしているのではないか
- 今回のようなミニマムな機能の場合、単一コンポーネントで記述した方がいいのではないか
以上、よろしくお願い致します。
該当のソースコード
html
1<!DOCTYPE html> 2<html lang="ja"> 3<head> 4 <meta charset="UTF-8"> 5 <title>TODO LIST</title> 6 <link rel="stylesheet" href="dist/css/app.css"> 7 <script src="https://use.fontawesome.com/e3ae05b8e6.js"></script> 8</head> 9<body> 10 11<div class="main"> 12 <h1 class="mainTitle">TODOS</h1> 13 <div id="app"> 14 <todo-list></todo-list> 15 </div> 16</div> 17 18 19<script src="dist/js/bundle.js"></script> 20</body> 21</html>
js
1import Vue from 'vue' 2 3// todo追加用コンポーネント 4Vue.component('todo-creator', { 5 props:['index'], 6 data:function(){ 7 return { 8 newTodoText:'', 9 errMsg:'' 10 } 11 }, 12 methods:{ 13 addItem: function(){ 14 if(this.newTodoText){ 15 let id = this.index + 1; 16 let text = this.newTodoText; 17 18 this.newTodoText = ''; 19 this.errMsg = ''; 20 this.$emit('add',id, text); 21 } else { 22 this.errMsg='入力が空です'; 23 } 24 } 25 }, 26 template: 27 `<div> 28 <div class="inputArea"> 29 <input type="text" class="inputText" v-model="newTodoText" placeholder="smothing todo task" 30 v-on:keydown.enter.shift="addItem"/> 31 </div> 32 <span class="error" v-if="errMsg">{{errMsg}}</span> 33 </div>` 34}) 35 36// todo削除用コンポーネント 37Vue.component('todo-delete', { 38 props:['index'], 39 methods:{ 40 deleteItem:function () { 41 this.$emit('del',this.index); 42 } 43 }, 44 template: 45 `<i class="fa fa-trash icon-trash" v-on:click="deleteItem" />` 46}) 47 48// todo完了用コンポーネント 49Vue.component('todo-done',{ 50 props:['index'], 51 methods:{ 52 doneItem:function () { 53 this.$emit('done',this.index); 54 } 55 }, 56 template: 57 `<i class="fa fa-circle-thin icon-check" v-on:click="doneItem" />` 58}) 59 60// todo編集用コンポーネント 61Vue.component('todo-edit',{ 62 props:['item', 'index'], 63 data:function(){ 64 return { 65 tempItem: { 66 id:this.item.id, 67 text: this.item.text, 68 isDone:this.item.isDone, 69 isEdit:this.item.isEdit 70 } 71 } 72 }, 73 methods:{ 74 editItem: function () { 75 if(!this.item.isDone){ 76 this.tempItem.isEdit = true; 77 this.focusItem(); 78 } 79 }, 80 focusItem: function () { 81 this.$refs.focusThis = []; 82 this.$nextTick(function () { 83 this.$refs.focusThis.select(); 84 }) 85 }, 86 editedItem: function () { 87 this.tempItem.isEdit = false; 88 this.$emit('edit',this.index, this.tempItem.text); 89 } 90 }, 91 template: 92 `<div style="display:inline"> 93 <span v-on:dblclick="editItem" v-if="!tempItem.isEdit">{{this.item.text}}</span> 94 <input ref="focusThis" type="text" class="editText" v-model="tempItem.text" v-if="tempItem.isEdit" v-on:keypress.enter="editedItem" @blur="editedItem"> 95 </div>` 96}) 97 98Vue.component('todo-list', { 99 data: function () { 100 return { 101 items: [ 102 { 103 id:1, 104 text: 'sample text1', 105 isDone: false, 106 isEdit: false 107 }, 108 { 109 id:2, 110 text: 'sample text2', 111 isDone: false, 112 isEdit: false 113 } 114 ], 115 searchWord:'' 116 } 117 }, 118 methods:{ 119 addItem: function(id, text){ 120 this.items.push({ 121 id, 122 text, 123 isDone:false, 124 isEdit:false 125 }); 126 }, 127 deleteItem: function (index) { 128 this.items.splice(index, 1) 129 }, 130 doneItem: function (index) { 131 this.items[index].isDone = !this.items[index].isDone; 132 }, 133 editItem: function (index, text) { 134 this.$nextTick(function () { 135 this.items[index].text = text; 136 }) 137 } 138 }, 139 computed: { 140 searchItem:function () { 141 let regexp = new RegExp('^' + this.searchWord + '[a-zA-Z0-9]*'); // 検索条件(前方一致)を定義 142 let data = this.items; // 現在のオブジェクトを保存 143 if (this.searchWord){ // 検索フォームに入力があった場合 144 data = this.items.filter(function (item) { // 前方一致でヒットしたオブジェクトを配列に格納する 145 return item.text.match(regexp) 146 }) 147 } 148 return data // ヒットしたもののみが格納された配列を返す 149 } 150 }, 151 template: 152 `<div> 153 <div class="form"> 154 <todo-creator v-bind:index="Object.keys(this.items).length" v-on:add="addItem"></todo-creator> 155 </div> 156 157 <div class="searchBox"> 158 <i class="fa fa-search searchBox__icon" aria-hidden="true" /> 159 <input type="text" class="searchBox__input" v-model="searchWord" /> 160 </div> 161 162 <ul class="list"> 163 <li class="list__item" v-bind:class="{ 'list__item--done': item.isDone }" v-for="(item, index) in searchItem"> 164 <todo-done v-bind:index="index" v-on:done="doneItem"></todo-done> 165 <todo-edit v-bind:item="item" v-bind:index="index" v-on:edit="editItem"></todo-edit> 166 <todo-delete v-bind:item="item" v-bind:index="index" v-on:del="deleteItem"></todo-delete> 167 </li> 168 </ul> 169 </div>` 170}) 171new Vue({el: '#app'}) 172 173
補足情報(FW/ツールのバージョンなど)
Vue.js 2.5.16
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/04/19 09:26