1,與表單進行雙向資料繫結
<script setup> import { ref } from 'vue' const msg = ref('Hello World!') </script> <template> <h1>{{ msg }}</h1> <input v-model="msg" /> </template>
相當於做了兩件事,1,將msg繫結input的value上;2,input的value變更時,將新value賦值給msg,類似下面的::value="msg" @input="updateValue"
2,與子元件進行雙向資料繫結
<!-- Parent.vue --> <script setup> import Child from './Child.vue' import { ref } from 'vue' const msg = ref('Hello World!') </script> <template> <h1>{{ msg }}</h1> <Child v-model="msg" /> </template> <!-- Child.vue --> <script setup> const model = defineModel() </script> <template> <span>My input</span> <input v-model="model"> </template> //相當於下面的老版本(3.4之前)的實現方式 <!-- Parent.vue --> <Child :modelValue="msg" @update:modelValue="$event => msg = $event" /> <!-- Child.vue --> <script setup> const props = defineProps(['modelValue']) const emit = defineEmits(['update:modelValue']) </script> <template> <input :value="modelValue" @input="emit('update:modelValue', $event.target.value)" /> </template>
//注意:父元件傳的值為undefined,子元件有預設值,這種情況將導致父元件的model跟子元件的model初始值不一致,不過,繫結關係還在,雙方任何改動,還是會使值同步。如下 // 子元件: const model = defineModel({ default: 1 }) // 父元件 const myRef = ref() <Child v-model="myRef"></Child>
defineModel:獲取父元素傳過來的屬性值,用法如下
父:<Child v-model='aaa'> //不帶引數,預設引數名稱是modelValue , 相當於 <Child v-bind:modelValue='aaa' v-on:update:modelValue='value=>modelValue=value'>
1,子:let model = defineModel()
2,子帶預設值:let model = defineModel({ default: 0 })
3,父必填:let model = defineModel({ required: true })
父帶引數:<Child v-model:first-name='aaa' ></Child> //不帶引數,預設引數名稱是modelValue
子:let model = defineModel(‘firstName’,{ default: 0 }); //first-name 可用firstName接收
父多個繫結:<Child v-model:first-name='aaa' v-model:last-name='bbb'></Child>
子:let model = defineModel(‘firstName’); let model = defineModel(‘lastName’);
v-model可帶修飾符:trim number lazy,及自定義修飾符
//帶指令基礎寫法 <!--Parent--> const myText = ref('') <Child v-model.trim="myText" /> <!--Child--> const model = defineModel(); <input type="text" v-model="model" />
//自定義指令,例如capitalize,把輸入的值首字母大寫 <!--Parent--> <Child v-model.capitalize="myText" /> <!--Child--> <script setup> //modifiers列印的值為:{ capitalize: true },與自定義修飾符保持一致 const [model, modifiers] = defineModel({ set(value) { if (modifiers.capitalize) { return value.charAt(0).toUpperCase() + value.slice(1) } return value } }) </script> <template> <input type="text" v-model="model" /> </template>
//上面自定義指令v-model老版本寫法如下: <!--Parent--> let myText = ref(''); <Child v-model.capitalize='myText' /> <!--Child--> <script setup> const props = defineProps({ modelValue: String, modelModifiers: { default: () => ({}) } }) const emit = defineEmits(['update:modelValue']) function emitValue(e) { let value = e.target.value if (props.modelModifiers.capitalize) { value = value.charAt(0).toUpperCase() + value.slice(1) } emit('update:modelValue', value) } </script> <template> <input type="text" :value="modelValue" @input="emitValue" /> </template>
v-model可以同時新增引數及修飾符,例如 let msg = ref(''), v-model:name.trim="msg"
總結:
表單:v-model是:value="msg" @input="updateValue" 的縮寫
let updateValue = ($e)=>{
msg.value = $e.target.value
}
子元件:v-model是:modelValue="msg" @update:modelValue="$value => msg = $value " 的縮寫
let msg = ref('');
<Child v-model='msg'/> 跟 <Child :modelValue="msg" @update:modelValue="$value => msg = $value " />一樣
defineModel
是一個便利宏。編譯器將其展開為以下內容:
- 一個名為
modelValue
的 prop,本地 ref 的值與其同步; - 一個名為
update:modelValue
的事件,當本地 ref 的值發生變更時觸發
及defineModel只用於子元件中, 是下面兩句的縮寫
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])