vue3的深入组件-组件 v-model

组件 v-model
基本用法​

v-model 可以在组件上使用以实现双向绑定。

从 Vue 3.4 开始,推荐的实现方式是使用 defineModel() 宏:

复制代码
<script setup>
const model = defineModel()

function update() {
  model.value++
}
</script>

<template>
  <div>Parent bound v-model is: {{ model }}</div>
  <button @click="update">Increment</button>
</template>

父组件可以用 v-model 绑定一个值:

复制代码
<script setup lang="ts">
import { useAppStore } from '@/store/modules/app'
const appStore =  useAppStore()
import modelChild from './components/test/modelChild.vue'
const textColor = computed(() => appStore.getTextColor)
appStore.initTheme()
const countModel = ref(10)
</script>

<template>
  <ConfigGlobal>
    <p :style="{'color':textColor}"  >p标签</p>
    {{ countModel }}
    <modelChild v-model="countModel"></modelChild>
   </ConfigGlobal>
  
</template>

显示如下:

defineModel() 返回的值是一个 ref。它可以像其他 ref 一样被访问以及修改,不过它能起到在父组件和当前变量之间的双向绑定的作用:

  • 它的 .value 和父组件的 v-model 的值同步;

  • 当它被子组件变更了,会触发父组件绑定的值一起更新。
    这意味着你也可以用 v-model 把这个 ref 绑定到一个原生 input 元素上,在提供相同的 v-model 用法的同时轻松包装原生 input 元素:

    child.vue

    // app.vue

底层机制

defineModel 是一个便利宏。编译器将其展开为以下内容:

  • 一个名为 modelValue 的 prop,本地 ref 的值与其同步;

  • 一个名为 update:modelValue 的事件,当本地 ref 的值发生变更时触发。

因为 defineModel 声明了一个 prop,你可以通过给 defineModel 传递选项,来声明底层 prop 的选项:

子组件

复制代码
<script setup>
const model = defineModel({required:true, default: 1 }) // 对应 model 参数
</script>

<template>
  <input v-model="model" type="text">
  <!-- <input v-model="age" type="number"> -->
</template>

父组件

复制代码
<script setup lang="ts">
const countModel = ref()
console.log(countModel.value,'countModel'); // undefined
</script>
<template>
  <ConfigGlobal>
    {{ countModel }}
    <modelChild v-model="countModel"></modelChild>
   </ConfigGlobal>
  
</template>

如果为 defineModel prop 设置了一个 default 值且父组件没有为该 prop 提供任何值,会导致父组件与子组件之间不同步。在下面的示例中,父组件的 countModel 是 undefined,而子组件的 model 是 1:

v-model 的参数
复制代码
//子组件
<script setup>
const title = defineModel('title')
</script>

<template>
  <input type="text" v-model="title" />
</template>


// 父组件
<script setup>
import { ref } from 'vue'
import MyComponent from './MyComponent.vue'
  
const bookTitle = ref('v-model argument example')
</script>

<template>
  <h1>{{ bookTitle }}</h1>
  <MyComponent v-model:title="bookTitle" />
</template>
不同属性绑定多个 v-model

父组件​

复制代码
<UserForm 
  v-model:username="user.name"
  v-model:age="user.age"
/>

子组件

复制代码
<script setup>
const username = defineModel('username') // 对应 username 参数
const age = defineModel('age') // 对应 age 参数
</script>

<template>
  <input v-model="username" type="text">
  <input v-model="age" type="number">
</template>
处理 v-model 修饰符

父组件

使用内置修饰符(如 .trim):

复制代码
<Child v-model.trim="text" />

子组件

复制代码
<script setup>
const [model, modifiers] = defineModel() // 解构出修饰符

// 根据修饰符调整值
const processedModel = computed({
  get: () => model.value,
  set: (value) => {
    if (modifiers.trim) {
      model.value = value.trim()
    } else {
      model.value = value
    }
  }
})
</script>

<template>
  <input v-model="processedModel" />
</template>
  • 使用自定义修饰符 .capitalize:
    创建一个自定义的修饰符 capitalize,它会自动将 v-model 绑定输入的字符串值第一个字母转为大写

父组件

复制代码
<Child v-model.capitalize="text" />

子组件​​

通过 set 选项处理修饰符逻辑

复制代码
<script setup>
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 修饰符

父组件

复制代码
<UserForm 
  v-model:username.trim="user.name"
  v-model:age.number="user.age"
/>

子组件​​

分别处理每个参数的修饰符:

复制代码
<script setup>
const [username, usernameModifiers] = defineModel('username')
const [age, ageModifiers] = defineModel('age')

// 处理 username 的 trim 修饰符
const processedUsername = computed({
  get: () => username.value,
  set: (val) => {
    username.value = usernameModifiers.trim ? val.trim() : val
  }
})

// 处理 age 的 number 修饰符
const processedAge = computed({
  get: () => age.value,
  set: (val) => {
    age.value = ageModifiers.number ? Number(val) : val
  }
})
</script>

<template>
  <input v-model="processedUsername" />
  <input v-model="processedAge" type="number" />
</template>
相关推荐
橙子家3 小时前
浏览器缓存之【基础键值存储】:Local storage 和 Session storage
前端
星星在线5 小时前
MusicFree:一个「All in One」的个人音乐服务器,让听歌回归简单
前端·后端
IT_陈寒6 小时前
Redis的SETNX并发问题让我加了三天班
前端·人工智能·后端
demo007x6 小时前
Docling 文档转换以及技术架构分析
前端·后端·程序员
京东云开发者7 小时前
京东市民服务又“上新”!这次是黑龙江“龙易办”
前端
袋鱼不重8 小时前
我的神奇同事,AI 用多了居然写了个 Open In Codex
前端·后端·ai编程
竹林8188 小时前
Web3表单签名验证:我用 wagmi 和 ethers 给 DApp 加了一个“免密登录”,踩坑记录全在这了
javascript
用户6990304848758 小时前
try catch使用场景 处理同步代码错误兼容用的
javascript·uni-app
雪碧聊技术8 小时前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript
Fireworks8 小时前
深入vue3源码解读 -- 1、响应式的基础概念
前端