Vue.jsを再入門する 4
前回記事
今回は編集機能と削除機能を実装します。
モーダルを発生させる
ボタンの設置
タスクの横にボタンを置き、押下時にモーダルが発生するようにします。
b-checkbox
の後ろに
<button class="button is-primary" v-on:click="editTask()">Edit</button>
を記述します。
モーダルの設置
モーダルを発生させるにはb-modal
を使用します。
<b-modal :active.sync="isModalActive" has-modal-card> </b-modal>
has-modal-card
を設定するとその中に設定したモーダルの中身がモバイルでも崩れずに見れるらしいです。とりあえず設定しておきます。
:active.sync
でモーダルをON/OFFします。
トリガーとなるisModalActive
はdata内に定義します。
data() { return { taskText: '', tasks: [], isModalActive: false } }
タスクの編集
editTask()
の実装をします。
この関数が呼ばれたらisModalActive
をtrue
にします。
editTask() { this.isModalActive = true }
これでモーダルが発生するようになりました!
実際に確認します。
モーダルの上にフォームを作る
今回は別Componentとして作っていきたいと思います。
ファイル作成
src/components
配下にEditModal.vue
というファイルを作ります。
Buefyのモーダルサンプルを見よう見まねでフォームを作ります。
<form action=""> <div class="modal-card" style="width: auto"> <header class="modal-card-head"> <p class="modal-card-title">Edit</p> </header> <section class="modal-card-body"> <b-field label="Task"> <b-input type="task" :value="task" placeholder="タスクを入力してください" required> </b-input> </b-field> </section> <footer class="modal-card-foot"> <button class="button" type="button">削除</button> <button class="button is-primary">完了</button> </footer> </div> </form>
modal-card
の詳細仕様がどこに書いてあるのか不明なのでサンプルを見ながら解説していきます。
modal-card
以下にはmodal-card-head
とmodal-card-body
、modal-card-foot
があります。
Modal Card API
modal-card-head
下の画像の上段のLogin
の部分がmodal-card-head
です。
modal-card-body
次にフォームが並んでいる中段がmodal-card-body
です。
modal-card-foot
ボタンが並んでいる下段がmodal-card-foot
です。
中には通常通りのhtmlを書いていきます。
見た目はこれで完了です。
削除ボタンを押下時の呼び出す関数をdeleteTask()
、完了ボタンを押下時に呼び出す関数をeditedTask()
とします。
コンポーネントを読み込む
親コンポーネント(ここではToDo.vue
)内で作成したコンポーネント(ここではEditModal
)を読み込みます。
<script>
内に
import EditModal from '@/components/EditModal'
と記述し、コンポーネントを読み込みます。
@
はsrcまでのパスです。
そしてexport default {
以下に
components: { 'edit-modal': EditModal },
を記述することで、コンポーネント内で<edit-modal>
タグとして扱うことができます。
最後にb-modal
以下にedit-modal
を記述し、見た目の完成です。
<b-modal :active.sync="isModalActive"> <edit-modal></edit-modal> </b-modal>
実際にこうなります。
親子の連携
以上で見た目は完了しましたが、実際に値が移動していません。
親コンポーネントから値の送信、子コンポーネントでの値の当て込み、子コンポーネントから親コンポーネントの関数実行まで一気にやります。
親から子へ
親コンポーネントから子コンポーネントへ値を渡すために子コンポーネントにpropsを設定します。
今回は配列のindexとtaskが
export default {
以下にこちらを追記します。
props: { 'task': String },
そして親コンポーネントに送るための値を設定し、v-bind
で子コンポーネントに値を渡します。
今回はformProps
という名前でモデルを用意しました。
<b-modal :active.sync="isModalActive"> <edit-modal v-bind="formProps" ></edit-modal> </b-modal>
formProps: { task: '' }
次にeditTask()
を修正し、editTask呼び出し時に編集対象のTaskの文字をeditingText
に代入するようにします。
editTask(task, index) { this.formProps.task = task this.isModalActive = true },
モーダルを発生させるボタンは以下のようにします。
<button class="button is-primary" v-on:click="editTask(task.message)">Edit</button>
これで親から子への送信は完了です。
子コンポーネントでの値の当て込み
次に受け取った値をモーダル内のテキストフィールドに入るようにします。
data
内にtaskText
を記述し、初期値としてpropsで受け取ったtask
を代入します。
data() { return { taskText: this.task } },
そして前回と同様にb-input
にv-model="taskText"
を設定するとモーダル発生時にテキストフィールドにtaskTextの値が入って表示されます。
この時点で実行すると、以下のようになります。
これで完了です
子から親の関数実行
次に子から親の関数を実行します。
これはカスタムイベントハンドラーを使用して実現します。
v-on
を使用してイベントを購読します。
<b-modal :active.sync="isModalActive"> <edit-modal v-bind="formProps" v-on:edited="editedTask" v-on:delete="deleteTask"></edit-modal> </b-modal>
edited
というイベントが発火した時にeditedTask
が実行され、delete
が発火した時にdeleteTask
を実行します。
editedTask
とdeleteTask
は一旦モーダルを消す実装のみをします。
editedTask() { this.isModalActive = false }, deleteTask() { this.isModalActive = false }
次に子にて、ボタンを押下された際に親のイベントを発火するようにします。
まずmodal-foot
内のボタンにv-on:click
を記述します。
<footer class="modal-card-foot"> <button class="button" type="button" v-on:click="deleteTaskChild()">削除</button> <button class="button is-primary" v-on:click="editedTaskChild()">完了</button> </footer>
次にdeleteTaskChild
、editedTaskChild
を実装します。
editedTask() { this.$emit('edited') }, deleteTask() { this.$emit('delete') }
$emit
を使用することで親で購読しているイベントを発火することができます。
実行してみます。
モーダルを消すことに成功しました。
削除を実装する。
次に削除の関数を実装します。
現在tasks
という配列を持っていますが、編集時のindexが判断できないため、editingIndex
をdata
内に宣言します。
次にリスト描画時のv-for
でindex
を取得するように追記します。
<div class="field task-field" v-for="(task, index) in tasks" v-bind:data="task" v-bind:key="task.text">
次にeditTask
関数内でeditingIndex
にindex
を代入するように追記します。
editTask(task, index) { this.formProps.task = task this.editingIndex = index this.isModalActive = true },
次に編集ボタンが呼び出すeditTask
の引数にindexを追加します
<button class="button is-primary" v-on:click="editTask(task.message, index)">Edit</button>
最後にdeleteTask
を実装して終わりです。
編集中のIndexの場所にあるtasks
内の要素を削除し、保存します。
deleteTask() { this.tasks.splice(this.editingIndex, 1) this.storeTasks() this.isModalActive = false }
これで削除機能が実装できました。
実行してみます。
削除ができました!
編集を実装する
編集機能の実装をします。
編集中の文字列は子がtaskText
という変数で持っているのでこれを親に渡します。
$emit
内で値を渡すには、this.$emit('イベント名', 値)
という風にします。
今回は親にtaskText
を渡すのみなので以下のようになります。
editedTaskChild() { this.$emit('edited', this.taskText) },
親のeditedTask()
は引数をもつようにeditedTask(task)
とします。
最後に、編集後のjson配列、置き換え、保存をしています。
editedTask(task) { var editedData = { message : task, done: this.tasks[this.editingIndex].done} this.tasks[this.editingIndex] = editedData this.storeTasks() this.isModalActive = false },
これで全部の機能が揃いました。
実行してみます。
再入門をして
Vue.jsの色々な機能を使用してみました。
まだまだ他にも色々な機能があり使いきれてはいないですが、今後も色々触っていきたいと思います。
今後、vuexも触っていきます。