{%hackmd BJrTq20hE %} ###### tags: `Vue` `composition API` # 從composition API 開始VUE的生活- v-model 資料的雙向綁定、自訂義組件的資料綁定、One-Way Data Flow 單向資料流 ## v-model v-model指令使用來雙向綁定資料與畫面渲染的資料。 v-model使用的標籤為 input、textarea、select 以下為基本的範例 ### input type="text" ```javascript= <script setup> const num = ref(0) ``` ```htmlembedded= <input type="text" v-model="num"> <h2>{{num}}</h2> </script> ``` 畫面與資料綁定 ![](https://i.imgur.com/vcIltvb.jpg) 當input的內容改變,const num = ref(0),同時也被改變並呈現在畫面上。 ![](https://i.imgur.com/i85WaZh.jpg) 這個時候的const num = ref("0123")資料型態變成字串了 [v-model修飾符](https://hackmd.io/HQqcF68vRi-MPYEM8-jIiQ?view#52-v-model%E4%BF%AE%E9%A3%BE%E7%AC%A6) ### input type="checkbox" ```javascript= <script setup> const data = ref(true) ``` ```htmlembedded= <input type="checkbox" v-model="data"> <label for="check" >checkbox</label> <h2>{{data}}</h2> </script> ``` ![](https://i.imgur.com/y8nNjGD.jpg) ![](https://i.imgur.com/aw68ljx.jpg) ### input type="checkbox" 與顯示所選內容 ```javascript= <script setup> const checkList = ref([]) </script> ``` 注意這邊的input內要有value這個屬性才會把透過v-model把值寫到checkList這個空陣列。 ```htmlembedded= <template> <input type="checkbox" id="Black Tea" value="Black Tea" v-model="checkList"> <label for="Black Tea">Black Tea</label> <input type="checkbox" id="Milk Tea" value="Milk Tea" v-model="checkList"> <label for="Milk Tea">Milk Tea</label> <input type="checkbox" id="Green tea" value="Green tea" v-model="checkList"> <label for="Green tea">Green tea</label> <h2>checkList:{{checkList}}</h2> </template> ``` ![](https://i.imgur.com/26WXMZw.jpg) ![](https://i.imgur.com/VA4bzd7.jpg) ### input type="radio" 與顯示所選內容 ```javascript= <script setup> const picked = ref('') </script> ``` 注意這邊的input內要有value這個屬性才會把透過v-model把值寫到picked這個空字串。 ```htmlembedded= <template> <input type="radio" id="male" value="male" v-model="picked"> <label for="male">Male</label> <input type="radio" id="female" value="female" v-model="picked"> <label for="female">Female</label> <h2>Gender:{{picked}}</h2> </template> ``` ![](https://i.imgur.com/prpD9jv.jpg) ![](https://i.imgur.com/Qtg96qm.jpg) ### select 與顯示所選內容 ```javascript= <script setup> const menu = ref('') const menuComputed = computed(()=> menu.value === ''? '還沒點餐' : menu ) </script> ``` ```htmlembedded= <template> <select name="menu" id="orderList" v-model="menu"> <option value="" disabled selected>請選擇一樣你想吃的東西</option> <option>牛排</option> <option>炒飯</option> <option>文字燒</option> <option>火鍋</option> </select> <h2>你的點餐:{{menuComputed}}</h2> </template> ``` ![](https://i.imgur.com/x844Hqd.jpg) ![](https://i.imgur.com/Jcn8bgr.jpg) ### select 多選 與顯示所選內容 多選的話menus要為空陣列 ```javascript= <script setup> const menus = ref([]) const menuComputed = computed(()=> menu.value === ''? '還沒點餐' : menu ) </script> ``` ```htmlembedded= <template> <select name="menu" id="orderList" v-model="menus" multiple> <option value="" disabled selected>請選擇一樣你想吃的東西</option> <option>牛排</option> <option>炒飯</option> <option>文字燒</option> <option>火鍋</option> </select> <h2>你的點餐:{{menuComputed}}</h2> </template> ``` ![](https://i.imgur.com/YvTmGQ4.jpg) ![](https://i.imgur.com/6RgGfGS.jpg) 補充select內的option也可以使用v-for指令 ```javascript= <script setup> const menus = ref([]) const options = ref(['牛排','炒飯','文字燒','火鍋']) const menuComputed = computed(()=> menu.value === ''? '還沒點餐' : menu ) </script> ``` ```htmlembedded= <template> <h2>option使用v-for</h2> <select name="menu" id="orderList" v-model="menus" multiple> <option value="" disabled selected>請選擇你想吃的東西</option> <option v-for="option in options" :key="option" :value="option">{{option}}</option> </select> <h2>你的點餐:{{menusComputed}}</h2> </template> ``` ### v-model與子元件的使用 父元件 :::success props內的modelValue與emits內的update:modelValue這兩個當子元件使用v-model綁定父元件的資料時是固定的不能改變。 ::: ```javascript= <script setup> const componentString = ref('APP') // 可以知道componentString有沒有被改變 watch(componentString,(newValue, oldValue)=>{ console.log('new', newValue); console.log('old', oldValue); }) ``` ```htmlembedded= <TestComponent v-model="componentString" /> <h3>{{componentString}}</h3> </script> ``` 子元件 :::success 1.元件內的input就不是使用v-model綁props.value了 而是使用v-bind綁定rops.value。 2.emit的部分所綁定的動作是input,其中update:modelValue這個"方法"當子元件有input且綁定父元件的資料時update:modelValue不能改變寫法。 3.所傳的資料是$event.target.value,就等於addEventListener('input',(e)=>{e.target.value})裡面的e.target.value ::: ```javascript= <script setup> const props = defineProps(['modelValue']) const emits = defineProps(['update:modelValue']) </script> ``` ```htmlembedded= <template> <h2>TestComponent</h2> <input :value="props.modelValue" @input="emits('update:modelValue', $event.target.value)"> </template> ``` ### 元件v-model是由props與emit這兩個組成 父元件 :::success 1.與上述的範例不同因為不是使用v-model綁定所以傳入資料的時候可以自訂。 2.因為沒有使用v-model所以要處理資料接收,固定使用@updata:model-value或是@updata:modelValue來接收資料 ::: ```javascript= <script setup> const componentString = ref('APP') const getData = (res)=>{ componentString.value = res } // 可以知道componentString有沒有被改變 watch(componentString,(newValue, oldValue)=>{ console.log('new', newValue); console.log('old', oldValue); }) </script> ``` ```htmlembedded= <template> <h2>元件v-model是由props與emit這兩個組成</h2> <TestComponentA :send-string="componentString" @update:model-Value="getData"/> <h3>{{componentString}}</h3> </template> ``` 子元件 :::success 1.元件內的input就不是使用v-model綁props.value了 而是使用v-bind綁定rops.value。 2.emit的部分所綁定的動作是input,其中update:modelValue這個"方法"當子元件有input且綁定父元件的資料時update:modelValue不能改變寫法。 3.所傳的資料是$event.target.value,就等於addEventListener('input',(e)=>{e.target.value})裡面的e.target.value ::: ```javascript= <script setup> const props = defineProps(['sendString']) const emits = defineProps(['update:modelValue']) </script> ``` ```htmlembedded= <template> <h2>componentA</h2> <input type="text" :value="props.sendString" @input="emits('update:modelValue', $event.target.value)"> </template> ``` 結果如下圖 原本 ![](https://i.imgur.com/gUzHYME.jpg) 在子元件輸入123後 ![](https://i.imgur.com/OBFXv4Z.jpg) watch也監測到了資料改變 ![](https://i.imgur.com/KGLBlGw.jpg) 延伸閱讀 --- [vue官方文件 v-model](https://vuejs.org/guide/components/events.html#usage-with-v-model) 內有子元件可以透過computed的get與set使用v-model,與v-model自訂修飾符。 ## One-Way Data Flow 透過把方法傳送到子元件執行,讓資料只留在父元件 父元件 ```javascript= <script setup> const write = ref('') function writeJack(){ write.value = 'Jack' </script> } ``` ```htmlembedded= <TestComponentB :ComponentWriteJackFn="writeJack"/> <input type="text" v-model="write"> ``` 子元件 ```javascript= <script setup> const props = defineProps(['ComponentWriteJackFn']) </script> ``` ```htmlembedded= <template> <h2>componentB</h2> <button type="button" @click="props.ComponentWriteJackFn" >writeJack</button> </template> ``` 參考資料 --- [Vue3 + Vite 快速上手 Get Startrd EP4 - v-model 資料的雙向綁定 / 自訂義組件的資料綁定 / One-Way Data Flow 單向資料流](https://www.youtube.com/watch?v=firPRbhoX7o)