第7弾です。
前回までの記事はこちら。
【Vue】おれおれチュートリアル Ⅰ - 山崎屋の技術メモ
【Vue】おれおれチュートリアル Ⅱ - 山崎屋の技術メモ
【Vue】おれおれチュートリアル Ⅲ - 山崎屋の技術メモ
【Vue】おれおれチュートリアル Ⅳ - 山崎屋の技術メモ
【Vue】おれおれチュートリアル Ⅴ - 山崎屋の技術メモ
【Vue】おれおれチュートリアル Ⅵ - 山崎屋の技術メモ
今回は見た目の改善を行います。
- 作者: 川口和也,喜多啓介,野田陽平,手島拓也,片山真也
- 出版社/メーカー: 技術評論社
- 発売日: 2018/09/22
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
- 作者: mio
- 出版社/メーカー: シーアンドアール研究所
- 発売日: 2018/05/29
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
Todo リストの行の高さを調節する
第5回のチュートリアルで Element のストライプテーブルを使用して見た目をおしゃれにしましたが、行の高さが固定されていて調節の仕方が分からないと書きました。
↓↓↓ ちょっと1行1行が高いですよね。
最終的な HTML を確認すると、<table> タグ内の <td> に padding 12px のスタイルが定義されており、これが変更できなくて困っていました。
調べたら解決方法がありました!
ElementUI に Scoped CSS が適用されない問題対応策 - Qiita
スコープ付き CSS · vue-loader
Vue の ディープセレクタという機能を使うようです。
今回は「.list」クラス内の <td> タグの padding を 5px にします。Todo.vue の <style> タグ内の最後に以下の記述を追加します。
.list >>> td { padding: 5px; }
これで子コンポーネントのスタイルを調整することができます。sass の場合は「>>>」の変わりに「/deep/」と記載します。
行間がいい感じになりました。
削除時にアニメーションを追加
現状、削除ボタンを押すと瞬時に対象の行が消えて、下の行が上に詰まってきます。
どの行が消えたのか分かりやすいようにゆっくりフェードアウトするようなアニメーションを付けたいと思います。
うーん、結構めんどくさいことになってしまいました。Element のコンポーネントに細かい動作を設定するのは結構はまります。ここは Element 使うべきではなかったかも知れません。
まず、<el-table> タグに row-class-name を追加します。生成される <tr> タグに class 属性が追加されます。JavaScript で DOM を取得するときに使います。
<el-table :data="list" stripe class="list" row-class-name="todo-row"> <!-- 追加 -->
削除時に呼び出すメソッドの引数は scope.row ではなく、 scope 自体を渡すようにします。JavaScript で scope の $index プロパティにアクセスしたいので。
変更前:
<el-button @click="deleteTask(scope.row)" type="danger" plain size="small">削除</el-button>
変更後:
<el-button @click="deleteTask(scope)" type="danger" plain size="small">削除</el-button>
そして deleteTask メソッドは大幅に変更し、生の js でゴリゴリやっていきます。コメントを細かく入れたので、何の処理をしているのか確認してください。
deleteTask(scope) { // TR タグを全て取得 const els = document.getElementsByClassName('todo-row') // 削除ボタンが押された行に deleting クラスを追加 els[scope.$index].classList.add('deleting') // this を別変数で保管 const self = this // setTimeout に渡す関数を定義 const f = function() { // list から 削除する要素を削除 self.list = self.list.filter(e => e !== scope.row) // 全ての TR タグから deleting クラスを削除 for(var i=0; i < els.length; i++){ els[i].classList.remove('deleting'); } } // 0.5 秒後に削除を実施する setTimeout(f, 500); }
最後に css で .delete クラスのアニメーション定義を追加します。0.5 秒をかけて、要素を透明にします。
@keyframes fadeout { 0% { opacity: 1; } 100% { opacity: 0; } } .list >>> .deleting { animation: fadeout 0.5s ease 0s forwards; }
これで削除時にゆっくり消えてなくなるアニメーションが実装できました。
まとめ
今回はデザインの修正を行いました。
ここまでのコードは GitHub にあります。「oreore7」でタグが打ってあります。
GitHub - yyama694/ore-todo: 【vue 】おれおれチュートリアル
最後に Todo.vue の全量を乗せておきます。
<template> <div> <h1>Todo List</h1> <el-input ref="new_task" class="task-input" placeholder="追加するタスクを入力してください。" v-model="newTask" @keydown.enter.native="addTask"></el-input> <el-button type="primary" plain @click="addTask">追加</el-button> <el-table :data="list" stripe class="list" row-class-name="todo-row"> <el-table-column style="padding: 8px"> <template slot-scope="scope"> <span :class="{ complete: scope.row.isComplete }">{{ scope.row.value }}</span> </template> </el-table-column> <el-table-column> <template slot-scope="scope"> <el-button @click="scope.row.isComplete=true" type="primary" plain size="small" v-if="!scope.row.isComplete">達成</el-button> <el-button @click="scope.row.isComplete=false" type="primary" plain size="small" v-if="scope.row.isComplete">戻す</el-button> <el-button @click="deleteTask(scope)" type="danger" plain size="small">削除</el-button> </template> </el-table-column> </el-table> </div> </template> <script> export default { data() { return { list: [ { id:1, value: "たまご買う", isComplete: false }, { id:2, value: "図書館に本を返す", isComplete: false }, { id:3, value: "宅急便を受け取る", isComplete: false } ], newTask: "", nextId: 4 } }, methods: { addTask() { if(!this.newTask.trim()) { return } this.list.push({ id: this.nextId++, value: this.newTask, isComplete: false }) this.newTask = "" }, deleteTask(scope) { // TR タグを全て取得 const els = document.getElementsByClassName('todo-row') // 削除ボタンが押された行に deleting クラスを追加 els[scope.$index].classList.add('deleting') // this を別変数で保管 const self = this // setTimeout に渡す関数を定義 const f = function() { // list から 削除する要素を削除 self.list = self.list.filter(e => e !== scope.row) // 全ての TR タグから deleting クラスを削除 for(var i=0; i < els.length; i++){ els[i].classList.remove('deleting'); } } // 0.5 秒後に削除を実施する setTimeout(f, 500); } }, mounted: function() { this.$refs.new_task.focus() } } </script> <style scoped> .list { width: 80%; margin: auto; text-align: left; } .complete { text-decoration: line-through; } h1 { position: relative; line-height: 1.4; } h1:before { font-family: "Font Awesome 5 Free"; content: "\f00c"; font-size: 0.7em; left: 0; top: 0; color: #5ab9ff; } .task-input { width: 60%; } .list >>> td { padding: 5px; } @keyframes fadeout { 0% { opacity: 1; } 100% { opacity: 0; } } .list >>> .deleting { animation: fadeout 0.5s ease 0s forwards; } </style>
それでは今日はここまで。ヴァ~イ。
- 作者: 川口和也,喜多啓介,野田陽平,手島拓也,片山真也
- 出版社/メーカー: 技術評論社
- 発売日: 2018/09/22
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
- 作者: mio
- 出版社/メーカー: シーアンドアール研究所
- 発売日: 2018/05/29
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る