前置き
input type="checkbox"
チェックボタン部分のみを
コンポーネントにする時のコードを
書いています✍
シュガーシンタックスv️-model
のおさらいから
実際のコンポーネントの
サンプルコードなどを
載せていきます🍀
参考:
Checkbox の Vue コンポーネントを作成する Tips
【Vue.js 再入門】 v-model を正しく理解して親子間コンポーネントのデータ伝播をマスターする
【Vue】Input内の値をv-modelのように親子間でバインドさせる方法【サンプルあり】
【Nuxt.js】ネストしたコンポーネントでv-modelの変更を親に反映させる
【Nuxt.js】フォームをコンポーネント化した時のメモ(子Componentで変更されたv-modelの値を親に反映する)
おさらい
v-model
はシュガーシンタックスv-bind:value
, v-on:input
これらを簡単に書けるものでした🌟
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<template> <input type="text" :value="value" @input="$emit('input', $event.target.value)" > </template> <script lang="ts"> export default { props: { value: { type: String, default: 'ハロー' } }, } </script> |
この例はtype="text"
ですが、
それぞれのtype
や
入力タグに合わせた
属性のバインディング
そしてイベントにしてくれます💡
type="input"
,textareaタグ
は:value
と@input
type="checkbox"
,type="radio"
は:checked
と@change
select
タグは:value
と@change
今回はチェックボックスなので:checked
と@change
ですね💡
パターン1: 定番
まずは定番の型。
おさらいでやったtype="text"
をtype="checkbox"
バージョンにしただけです。
@input
でも動きますが、
意味的にも@change
が良いですね🍀
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<template> <label class="label"> <input type="checkbox" :checked="checked" @change="$emit('input', $event.target.checked)" /> </label> </template> <script> export default { props: { checked: { type: Boolean, default: false, }, }, } </script> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<template> <div class="page"> <InputCheckbox v-model="isChecked" /> <p>{{ isChecked }}</p> </div> </template> <script> export default { data() { return { isChecked: '', } }, } </script> |
デザインカスタムをするなら…
input
のデザインは変えられないため、input
を見えないようにし、span
で装飾をする必要がありますね💫
それを踏まえるとこんな感じ💡
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
<template> <label class="label"> <input class="input" type="checkbox" :checked="checked" @input="$emit('input', $event.target.checked)" /> <span class="mark"></span> <span class="text">{{ text }}</span> </label> </template> </template> <script> export default { props: { checked: { type: Boolean, default: false, }, text: { type: String, default: '', }, }, } </script> <style lang="scss" scoped> .label { padding: 12px 8px; display: flex; align-items: center; cursor: pointer; &:hover > .mark { background: #dddddd !important; border: solid 2px #008eff; } .input { margin: 0; width: 0; opacity: 0; } .input:focus + .mark { background: #dddddd !important; border: solid 2px #008eff; } .input:checked + .mark { border: solid 2px #008eff; background: #ffffff; } .input:checked + .mark::before { content: ''; display: block; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -45%); width: 80%; height: 80%; background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="%23008EFF" d="M20.285 2l-11.285 11.567-5.286-5.011-3.714 3.716 9 8.728 15-15.285z"/></svg>') no-repeat center; background-size: contain; } .mark { position: relative; top: 0; left: 0; display: block; width: 32px; height: 32px; border: solid 2px #93cfff; background: #ffffff; border-radius: 4px; } .text { margin-left: 12px; display: block; font-size: 18px; font-weight: bold; } } </style> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<template> <div class="page"> <InputCheckbox v-model="isChecked" text="同意する" /> {{ isChecked }} </div> </template> <script> export default { data() { return { isChecked: '', } }, } </script> |
パターン2: 子でv-model
親でv-model
はあっても
子でv-model
って
全然見たことないですよね?👀
子でチェックのON/OFFを
まとめて管理できるので、
使えると良いな〜😀💭
と思っていたら、
コードを書いてる記事を発見✨🔍
こんな感じです🍀
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<template> <label> <input type="checkbox" v-model="inputedValue" /> {{ checked }} </label> </template> <script> export default { model: { prop: 'checked', event: 'change', }, props: { checked: { type: Boolean, }, }, computed: { inputedValue: { get() { return this.checked }, set(newValue) { this.$emit('change', newValue) }, }, }, } </script> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<template> <div class="page"> <InputCheckbox v-model="checked" /> </div> </template> <script> export default { data() { return { checked: '', } }, } </script> |
なんと親でも子でもv-model❗️笑
どういうこと❓と思っていたらscript
に見慣れないmodel
というものがありました。
Vueの公式を探して発見🔍
#model
こんな使い方もあるんですね…✨👏
参考:
【Nuxt.js】ネストしたコンポーネントでv-modelの変更を親に反映させる
【Vue.js 再入門】 v-model を正しく理解して親子間コンポーネントのデータ伝播をマスターする
【Nuxt.js】フォームをコンポーネント化した時のメモ(子Componentで変更されたv-modelの値を親に反映する)
そういえばVue3の変更点は
なんだったけな〜と思っていたら、
同じ箇所で複数使用できる、でした。
やりたいこととは違いますが、
備忘録的に残しておきます🌟
Vue3でv-modelがどう変わったか
これはNG
パッと思いついて
やりがちなのは、v-model
の値をprops
で
親から渡す…
こんな感じではないでしょうか。
1 2 3 4 5 6 7 8 9 10 11 |
<template> <label> <input type="checkbox" v-model="checked" /> </label> </template> <script> export default { props: ['checked'], } </script> |
1 2 3 4 5 |
<template> <div class="page"> <InputCheckbox checked="true" /> </div> </template> |
しかしこれだと
「読み書き」の「読み」
しかできないんです。
実際、チェックを触らなければ
エラーはないのですが、
つけ外しを行うとエラーになります💥✋
まとめ
form
要素のコンポーネントを
パターン化しておきたいな〜
と思って今回はcheckbox
に✍
type="text"
以外は
結構ややこしくて
苦戦しています😵💦笑
でもこれが理解できたら
すごく便利だし、form
要素ってinput
のtype
も
他のタグも入れたら結構あるし、
コンポーネントにして
スッキリ分けたいじゃないですか…🧹
なので各要素の記事と、
各要素の良いコードを抜粋して
全部を一覧で見れる記事を
書こうと思っています…🎈🧸