2019.11.19
Vueでカクテルデータベースをリファインする話#23【syncとオブジェクト】
いつまでこのプロダクトの開発してんだよ・・・・・・
思ったより時間取られた事象についてお話します。
話の流れとしては
前回の続きなんですが、より大きな規模でのsyncをしたい、って時の手法ですね。具体例挙げた方がよさそうですね。
<template>
<div id="container">
<category-secelt v-bind:edit-mode="editMode"
v-bind:selected-category.sync="selectedCategory"
v-bind:selected-middle.sync="selectedMiddle"
></category-secelt>
<br>
<NameAndDrescription
v-bind:edit-mode="editMode"
v-bind.sync="detailEditObj"
></NameAndDrescription>
</div>
</template>
<script>
import CategorySecelt from "./component/CategorySelect"
import NameAndDrescription from "./component/NamesAndDescription"
export default {
components: {
CategorySecelt,NameAndDrescription
},
data() {
return {
editMode:"Brand",
selectedCategory:null,
selectedMiddle:null,
detailEditObj:{
name:"",
name_eng:"",
strength:null,
description:"",
youtube:"",
youtube_time_hour:null,
youtube_time_minute:null,
youtube_time_second:null,
link_txt:"",
link_url:"",
is_major:false,
is_like:false,
input_image:null,
uploadImageUrl:null,
},
}
},
async created(){
//フォームの各種ボックス用意
//if (!this.brand_id){return}//もしbrand_idがなければ空でいい
},
}
</script>
要するとこういうことがやりたいんですよね。あ、Selectのスペルミスは気にしないで下さい()
オブジェクトを定義する必要あるのかどうかはわかりませんがこのようにオブジェクトのデフォルト値を定義し、プロパティを別々にbindしないで、オブジェクトにまとめてbindする、っていうのをやりたくて1日溶かしました。
で、まず記法の説明からですね。
<NameAndDrescription
v-bind:edit-mode="editMode"
v-bind.sync="detailEditObj"
></NameAndDrescription>
ここもタイポしてんじゃん・・・・・・候補入力してたから気づかなかった・・・・・・
後ろのオブジェクト名に気が行きがちですけど、実はちょっと書き方が変わってて
v-bind.syncで定義します。そう、ぶちこむ先のプロパティ名を記載しないんですよね。
ここ普通に見逃してて1日無駄にしました・・・・・・。
で、子コンポーネントの方ですね。
まだ仕組みを完全に理解してないので、とりあえず警告なしに動いたコードを載せます。
<v-text-field
:value="name"
@input="$emit('update:name', $event)"
:counter="255"
label="名前"
required
></v-text-field>
実際に動くコードがこちらです。
ちょっといろいろ特殊なんですが、これは他のサイトでは触れられてない書き方ですね。なんでこうなったのかというと
僕がVuetifyを使ってるからなんですね。
前回お話した通り、双方向バインディングの流れとしては、子コンポーネントは渡したい値と共に$emitでイベントを放出することで、(親の知らないところで値を変えることなく)双方向のバインディングを実現させています。
で、その渡す値って基本的には
$event.target.valueなんですよ。ここにvalue値、つまりフォームに入力された値が入ってるわけなので。で、それを親コンポーネントにupdate:xxxxイベントで渡し、バインドしてる親コンポーネントのオブジェクトに伝えることで同期としてる、って感じです。
じゃあこの$eventがそのままinput値になってるのは何故か。
正直それはわからないです
ただそれが発覚したのは、VueコンソールのEventを見てたらわかりました。
こういう画面あるんですけど、$eventでpayloadとして渡されてるのが、フォームに入力された文字列なんですよね。でもこれ、子コンポーネントが発火してるイベントじゃなくてVtextFieldが発火してるinputイベントなんですよ。
その上にあるupdate:nameが親コンポーネントに渡してるイベントの実体だと思われます。
じゃあなんでこの発火順なんだろう
ところで、公式リファレンス見てたらこういう記述がありました。もしかして、そもそもtarget.valueとか要らなかった説・・・・・・?
むしろ$eventそのものをemitしてconsole.logして、なんとかして中身見た方がよかったかも知れん感はする・・・・・・でも正直このevent拾えてない気がするっていうか、Vuetifyコンポーネントが内部的になんかやってる感じもしなくもないし、ちょいびみょう感はする・・・・・・
まぁアレです、Vueのことわかった気になってて、実はまだまだ学習すべき要項は多かった、って話です。
ただsyncを使うことでコード量がめちゃくちゃ減らせるので、次回作以降に大活躍しそうです。フォーム部品も分けられるようになったし。んじゃまたどっかで詰まるまでゴリゴリ実装しま~す。
11月中に終わるかなぁ