v-model

CaoJianbang發表於2024-10-22

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"

<script setup>
import { ref } from 'vue'

const msg = ref('Hello World!')
let updateValue = ($e)=> {
msg.value = $e.target.value
}
</script>

<template>
<h1>{{ msg }}</h1>
<input :value="msg" @input="updateValue"/> //:是v-bind的縮寫,@是v-on的縮寫 ,input事件:當input的value改變是觸發
</template>

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'])

相關文章