溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

vue3中的v-model怎么使用

發(fā)布時(shí)間:2023-04-25 14:55:27 來(lái)源:億速云 閱讀:100 作者:zzz 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹“vue3中的v-model怎么使用”的相關(guān)知識(shí),小編通過(guò)實(shí)際案例向大家展示操作過(guò)程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“vue3中的v-model怎么使用”文章能幫助大家解決問(wèn)題。

綁定單個(gè)屬性

基礎(chǔ)綁定

以 自定義組件 CustomInput 舉例

<script setup>
    const txt = ref('');
 </script>
 
 <template>
  <CustomInput v-model="txt" />
 </template>

v-model 會(huì)被展開(kāi)為如下的形式

<CustomInput
  :modelValue="txt"
  @update:modelValue="newValue => txt = newValue"
/>

<CustomInput> 組件內(nèi)部需要做兩件事:

  • 將內(nèi)部原生 <input> 元素的 value attribute 綁定到 modelValue prop

  • 當(dāng)原生的 input 事件觸發(fā)時(shí),觸發(fā)一個(gè)攜帶了新值的 update:modelValue 自定義事件

這里是相應(yīng)的代碼:

<script setup>
const props = defineProps({
  'modelValue': String,
})
const emit = defineEmits(["update:modelValue"])
</script>

<template>
    <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
</template>

有些人會(huì)覺(jué)得這種寫(xiě)法過(guò)于繁瑣,會(huì)導(dǎo)致標(biāo)簽代碼變得冗長(zhǎng)

另一種在組件內(nèi)實(shí)現(xiàn) v-model 的方式是使用一個(gè)可寫(xiě)的,同時(shí)具有 getter 和 setter 的 computed 屬性

computed 綁定

使用computed 屬性時(shí), get 方法需返回 modelValue prop,而 set 方法需觸發(fā)相應(yīng)的事件

<script setup>
const value = computed({
  get() {
    return props.modelValue
  },
  set(value) {
    emit("update:modelValue", value)
  }
})
</script>

<template>
 <input v-model="value" />
</template>

這種寫(xiě)法可以簡(jiǎn)化標(biāo)簽中的屬性,邏輯清晰

單個(gè)屬性可以使用 v-model 輕松搞定,如果多個(gè)屬性都需要雙向綁定呢?

v-model 綁定多個(gè)屬性

默認(rèn)情況下,v-model 在組件上都是使用 modelValue 作為 prop,并以 update:modelValue 作為對(duì)應(yīng)的事件

但我們可以通過(guò)給 v-model 指定一個(gè)參數(shù)來(lái)更改這些名字:

<template>
    <CustomInput v-model:first-name="first" v-model:last-name="last" />
</template>

同樣的,也可以用兩種方式綁定,只是 prop 從原來(lái)的 modelValue 變?yōu)榱藗魅氲膮?shù)名,對(duì)應(yīng)的事件也變成了 update:參數(shù)名

 <script setup>
 const props = defineProps({
  firstName: String,
  lastName: String,
})
// 在computed中 使用
const emit = defineEmits(['update:firstName', 'update:lastName'])
</script>

<template>
  <input
    type="text"
    :value="firstName"
    @input="$emit('update:firstName', $event.target.value)"
  />
  <input
    type="text"
    :value="lastName"
    @input="$emit('update:lastName', $event.target.value)"
  />
</template>

綁定對(duì)象

在一個(gè)復(fù)雜的組件中,如果多個(gè)字段需要雙向綁定,如果使用上文所示方法的話,會(huì)有一些繁瑣

介紹兩種雙向綁定對(duì)象的做法

定義父組件 searchBar 為一個(gè)復(fù)雜表單組件

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

const modelValue = ref({
  keyword: "123",
  selectValue: "",
  options: [
    {
      label: "全部",
      value: ""
    },
    {
      label: "a1",
      value: "1"
    },
    {
      label: "a2",
      value: "2"
    },
  ]
})
</script>

<template>
    <searchBar v-model="modelValue" />
</template>

那么在 searchBar 組件內(nèi),我們接收 modelValue 并定義類(lèi)型為 Object

<template>
  <div>
    <!-- <input type="text" v-model="modelValue.keyword"> 可以實(shí)現(xiàn)雙向綁定 -->
    <input type="text" 
      :value="modelValue.keyword"
      @input="handleKeywordChange"
    >
    <select v-model="modelValue.selectValue">
      <option v-for="o in modelValue.options" :key="o.value" :value="o.value">
        {{ o.label }}
      </option>
    </select>
  </div>
</template>

<script lang="ts" setup>

const props = defineProps({
  modelValue: {
    type: Object,
    default: () => ({})
  }
})

const emit = defineEmits(["update:modelValue"]);

// 以 input 舉例
const handleKeywordChange=(val)=>{
  emit("update:modelValue",{
    ...props.modelValue,
    keyword:val.target.value
  })
}
</script>

如果傳入對(duì)象的話,如注釋所介紹的那樣
<input type="text" v-model="modelValue.keyword">雖然可以直接進(jìn)行雙向綁定,但是這樣會(huì)破壞單項(xiàng)數(shù)據(jù)流

和上文的 emit 觸發(fā)事件一樣,但是傳遞的數(shù)據(jù)則變成了對(duì)象

雖然使用 emit 可以觸發(fā)雙向綁定,但是過(guò)于繁瑣,下面介紹一種更優(yōu)雅的寫(xiě)法,可以說(shuō)是一種奇技淫巧 -- computed + prxoy

如果使用 computed 綁定,你可能會(huì)寫(xiě)出這種代碼

<template>
      <input type="text" v-model="model.keyword">
 </template>
 
<script lang="ts" setup>

const model = computed({
  get() {
    return props.modelValue
  },
  set(value) {
    // console.log(value) // 發(fā)現(xiàn)沒(méi)有打印
     emit("update:modelValue", {
      ...props.modelValue,
       keyword: value
     })
  }
})
<script>

但是當(dāng)你輸入的時(shí)候,你會(huì)發(fā)現(xiàn)并沒(méi)有觸發(fā) setter, 因?yàn)?nbsp;computed 會(huì)做一層代理,代理對(duì)象沒(méi)有發(fā)生修改

如果想要觸發(fā) setter ,如下圖:

// 只有這樣才會(huì)變化
 model.value = {
   keyword:"asdfad"
 }

這種方法無(wú)法觸發(fā) setter,也就無(wú)法雙向綁定,該怎么辦呢?

getter 中返回 一個(gè) 代理對(duì)象!getter 中返回 一個(gè) 代理對(duì)象!getter 中返回 一個(gè) 代理對(duì)象!

因?yàn)?proxy代理的對(duì)象是和被代理對(duì)象屬性是保持一致的,所以我們使用 proxy 包裹原對(duì)象

那么 v-model 綁定的是代理之后的對(duì)象,如果代理對(duì)象屬性發(fā)生了改變,則會(huì)觸發(fā)代理對(duì)象中的 set 方法,此時(shí)我們可以觸發(fā) emit

const model = computed({
  get() {
    return new Proxy(props.modelValue, {
      set(obj, name, val) {
        emit("update:modelValue", {
          ...obj,
          [name]: val
        })
        return true
      }
    })
  },
  set(value) {
    emit("update:modelValue", {
      ...props.modelValue,
      keyword: value
    })
  }
})

修飾符

我們知道 v-model 有一些內(nèi)置的修飾符,例如 .trim,.number 和 .lazy。

在某些場(chǎng)景下,我們可能想要一個(gè)自定義組件的 v-model 支持自定義的修飾符。

我們來(lái)創(chuàng)建一個(gè)自定義的修飾符 capitalize,它會(huì)自動(dòng)將 v-model 綁定輸入的字符串值第一個(gè)字母轉(zhuǎn)為大寫(xiě):

  <CustomInput v-model.capitalize="txt" />

我們添加了capitalize修飾符,他會(huì)被自動(dòng)傳入到 prop 中的 modelModifiers 中

<script setup>
const props = defineProps({
  modelValue: String,
  modelModifiers: {
    default: () => ({})
  }
})

const 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 :value="modelValue" @input="emitValue" />
</template>

關(guān)于“vue3中的v-model怎么使用”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI