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

    <script setup> const model = defineModel() </script> <template> My input </template>

    // app.vue

    <script setup> import Child from './Child.vue' import { ref } from 'vue'

    const msg = ref('Hello World!')
    </script>

    <template>

    {{ msg }}

    <Child v-model="msg" /> </template>
底层机制

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

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

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

    <script setup> const props = defineProps(['modelValue']) const emit = defineEmits(['update:modelValue']) </script> <template> </template> <template> <ConfigGlobal>

    p标签

    {{ foo }} <modelChild :modelValue="foo" @update:modelValue="$event => (foo = $event)"></modelChild> </ConfigGlobal> </template>

因为 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>
相关推荐
姑苏洛言13 分钟前
编写产品需求文档:黄历日历小程序
前端·javascript·后端
知识分享小能手37 分钟前
Vue3 学习教程,从入门到精通,使用 VSCode 开发 Vue3 的详细指南(3)
前端·javascript·vue.js·学习·前端框架·vue·vue3
姑苏洛言1 小时前
搭建一款结合传统黄历功能的日历小程序
前端·javascript·后端
hackchen1 小时前
Go与JS无缝协作:Goja引擎实战之错误处理最佳实践
开发语言·javascript·golang
你的人类朋友2 小时前
🤔什么时候用BFF架构?
前端·javascript·后端
知识分享小能手2 小时前
Bootstrap 5学习教程,从入门到精通,Bootstrap 5 表单验证语法知识点及案例代码(34)
前端·javascript·学习·typescript·bootstrap·html·css3
一只小灿灿3 小时前
前端计算机视觉:使用 OpenCV.js 在浏览器中实现图像处理
前端·opencv·计算机视觉
前端小趴菜053 小时前
react状态管理库 - zustand
前端·react.js·前端框架
Jerry Lau3 小时前
go go go 出发咯 - go web开发入门系列(二) Gin 框架实战指南
前端·golang·gin