组件 v-model

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

1. v-model双向绑定

1.1 HTML表单元素v-model双向绑定

  • 原生的表单元素 使用v-model双向绑定

    <input v-model="searchText" />
    
  • 模板编译器会对上面的 v-model 进行如下更冗长的等价展开

    • 将组件实例上的searchText绑定给input的value属性
    • 监听input元素的输入事件,触发对应的监听函数执行,监听函数从输入事件中获取到输入的值,将输入的值更新给组件实例上的searchText,然后由于修改了响应式数据,引发重新渲染。
    <input:value="searchText"@input="searchText = $event.target.value"
    />
    

示例

MyInput.vue
<template>{{ searchText }}<input type="text" v-model="searchText"> <br/><!-- 将被展开为如下形式(以下,同上面等价) --><!-- <input type="text" :modelValue="searchText" @input="searchText = $event.target.value"> --></template><script>export default {name: 'MyInput',data() {return {searchText:''}}}</script><style lang="scss"></style>

1.2 自定义组件实现v-model

  • 可以在一个自定义组件上使用v-model

    <custom-input v-model="searchText"/>
    
  • 当在一个自定义组件上使用v-model时,v-model 会被展开为如下的形式
    • 将父组件实例上的searchText绑定给自定义组件的modelValue属性
    • 在父组件中,监听自定义组件的update:modelValue事件,当自定义组件使用$emit触发update:modelValue事件时(并携带了事件参数),对应的监听函数将执行,并且将事件参数的值更新给父组件实例上的searchText,由于修改了响应式数据,从而引发重新渲染(这个可以验证出来)
    <CustomInput:modelValue="searchText"@update:modelValue="newValue => searchText = newValue"
    />
    

示例

MyInput.vue
  • 父组件MyInput将自身的searchTex属性,通过v-model绑定给了自定义组件CustomInput组件。这实际上等价于做了2件事情:

    • 将父组件的searchText属性以props的形式传递给了CustomInput组件的modelValue的prop,
    • 并且给CustomInput组件绑定了对update:modelValue的事件监听,将事件触发时传递过来的事件参数,更新给了父组件MyInput的searchText属性,由于修改了响应式数据,从而引发重新渲染(这个可以验证出来)
<template>{{ searchText }}<custom-input v-model="searchText"/><!-- 将被展开为如下形式(以下,同上面等价) --><!--<custom-input :modelValue="searchText" @update:modelValue="newVal => searchText = newVal"/>--></template><script>import CustomInput from './CustomInput.vue';export default {name: 'MyInput',components:{CustomInput},data() {return {searchText:''}}}</script><style lang="scss"></style>
CustomInput.vue

子组件中仍然需要监听input事件,通过$emit触发update:modelValue事件,并且,将输入的值作为事件参数传递给事件监听函数

<template><input type="text" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)">{{ modelValue }}</template><script>export default {name: 'CustomInput',data() {return {}},props: ['modelValue']
}</script><style lang="scss"></style>

示例2(验证重新渲染)

  • 输入3次2,然后出现了如图的效果
  • 每次输入2的时候,子组件通过监听input事件,使用$emit触发update:modelValue事件,并且在输入的值后拼接上1作为事件参数,监听函数则把事件参数更新给了searchText,由于响应式数据发生了变化,所以重新渲染,所以输入框中,又是添加上了1,这证明了,修改了响应式数据后,子组件由于使用了prop,而得到了更新
MyInput.vue
<template>{{ searchText }}<custom-input v-model="searchText"/></template><script>
import CustomInput from './CustomInput.vue';
export default {name: 'MyInput',components:{CustomInput},data() {return {searchText:''}}}</script><style lang="scss"></style>
CustomInput.vue
<template><input type="text" :value="modelValue" @input="$emit('update:modelValue', $event.target.value + 1)">{{ modelValue }}
</template><script>export default {name: 'CustomInput',data() {return {}},props: ['modelValue'],updated() {console.log('updated...');}
}</script><style lang="scss"></style>

1.3 使用computed属性实现v-model双向绑定

  • 另一种在组件内实现 v-model 的方式是使用一个可写的,同时具有 getter 和 setter 的 computed 属性。

    • get 方法需返回 modelValue prop,而 set 方法需触发相应的事件:

示例1

MyInput.vue
<template>{{ searchText }}<custom-input v-model="searchText"/><!-- 将被展开为如下形式(以下,同上面等价) --><!--<custom-input :modelValue="searchText" @update:modelValue="newVal => searchText = newVal"/>--></template><script>
import CustomInput from './CustomInput.vue';
export default {name: 'MyInput',components:{CustomInput},data() {return {searchText:''}}}</script><style lang="scss"></style>
CustomInput.vue
  • 子组件CustomInput通过props接收modelValue属性,并将计算属性绑定给了input(计算属性的值来源于getter,即传入的modelValue这个prop)
  • 监听input元素的输入事件,并给计算属性赋值,触发计算属性的setter,在这个setter方法中,触发了update:modelValue事件,并将输入的值传递了过去,并更新给了searchText,然后引发重新渲染。
<template><input type="text" :value="value" @input="value = $event.target.value">{{ modelValue }}
</template><script>export default {name: 'CustomInput',data() {return {}},props: ['modelValue'],computed: {value: {get() {return this.modelValue},set(val) {this.$emit('update:modelValue', val)}}},
}</script><style lang="scss"></style>

示例2

Test.vue
<template><!-- 3. 使用computed属性实现v-model双向绑定 -->父组件中: {{ value1 }}<br/>子组件中: <custom-input2 v-model="value1"/></template><script lang="ts" setup>import { ref,reactive } from 'vue'import CustomInput2 from '@/views/test/CustomInput2.vue'const value1 = ref("zzhua")</script><style lang="scss"></style>
CustomInput2.vue
<template><!-- <input v-model="value" /> --> <!-- 以上等价于下方 --><input :value="value" @input="value = $event.target.value"/> {{ modelValue }} - {{ value }}<!-- 过程分析: 1. 父组件通过v-model指令, 将值通过props的方式传递给了子组件定义的modelValue2. 子组件中使用计算属性value, 读此属性返回modelValue, 修改此属性将触发 update:modelValue事件3. 当子组件初始化时, 模板被渲染, 拿到父组件传过来的modelValue, 模板中用到计算属性value的地方,计算属性value的get将被触发,于是返回modeValue的值4. 当修改子组件input框中的内容时, 将会把修改后的内容赋值给计算属性value, 计算属性value的set将会触发,将会把修改后的内容交给父组件的update:modelValue事件处理函数,从而子组件又开始更新渲染模板,于是跟第三步是一样的-->
</template><script lang="ts" setup>
import { computed } from 'vue'const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])const value = computed({get() {return props.modelValue},set(value) {emit('update:modelValue', value)}
})
</script>

3. v-model的参数

  • 默认情况下,v-model 在组件上都是使用 modelValue 作为 prop,并以 update:modelValue 作为对应的事件。

  • 我们可以通过给 v-model 指定一个参数来更改这些名字,如下:

    <MyComponent v-model:title="bookTitle" />
    
  • 在这个例子中,子组件应声明一个 title 的prop,并通过触发 update:title 事件更新父组件值:

    <!-- MyComponent.vue -->
    <script>
    export default {props: ['title'],emits: ['update:title']
    }
    </script><template><inputtype="text":value="title"@input="$emit('update:title', $event.target.value)"/>
    </template>
    
  • 可以在单个组件实例上,创建多个v-model双向绑定,组件上的每一个 v-model 都会同步不同的 prop,而无需额外的选项:

    <UserNamev-model:first-name="first"v-model:last-name="last"
    />
    
    <!-- UserName组件 -->
    <script>
    export default {props: {firstName: String,lastName: String},emits: ['update:firstName', 'update:lastName']
    }
    </script><template><inputtype="text":value="firstName"@input="$emit('update:firstName', $event.target.value)"/><inputtype="text":value="lastName"@input="$emit('update:lastName', $event.target.value)"/>
    </template>
    

示例

Test.vue

<template><!-- 4. v-model:attr 自定义v-model对应的prop参数名 --><!-- 默认情况下,v-model 在组件上都是使用 modelValue 作为 prop,并以 update:modelValue 作为对应的事件。我们可以通过给 v-model 指定一个参数来更改这些名字 --><CustomInput3 v-model:title="bookTitle" /><!-- 这等价于如下 --><!--<CustomInput3 :title="bookTitle" @update:title="newVal => bookTitle = newVal"/>--></template><script lang="ts" setup>import { ref,reactive } from 'vue'import CustomInput3 from '@/views/test/CustomInput3.vue';const bookTitle = ref("bookTitle")</script><style lang="scss"></style>

CustomInput3

<template><input type="text" :value="title" @input="$emit('update:title', $event.target.value)" />{{ title }}</template><script setup>defineProps(['title'])defineEmits(['update:title'])
</script>

5. v-model支持修饰符

在学习输入绑定时,我们知道了 v-model 有一些内置的修饰符,例如 .trim,.number 和 .lazy。在某些场景下,你可能想要一个自定义组件的 v-model 支持自定义的修饰符。

自定义一个v-model修饰符

  • 创建一个自定义的修饰符 capitalize,它会自动将 v-model 绑定输入的字符串值第一个字母转为大写

    <MyComponent v-model.capitalize="myText" />
    
  • 组件的 v-model 上所添加的修饰符,可以通过 modelModifiers prop 在组件内访问到。在下面的组件中,我们声明了 modelModifiers 这个 prop,它的默认值是一个空对象:

    • 注意这里组件的 modelModifiers prop 包含了 capitalize 且其值为 true,因为它在模板中的 v-model 绑定 v-model.capitalize=“myText” 上被使用了。
    • 有了这个 prop,我们就可以检查 modelModifiers 对象的键,并编写一个处理函数来改变抛出的值。在下面的代码里,我们就是在每次 元素触发 input 事件时将值的首字母大写:
    <script>export default {props: {modelValue: String,modelModifiers: {default: () => ({})}},emits: ['update:modelValue'],created() {console.log(this.modelModifiers) // { capitalize: true }}}
    </script><template><inputtype="text":value="modelValue"@input="$emit('update:modelValue', $event.target.value)"/></template>
    

v-model参数 + 修饰符

对于又有参数又有修饰符的 v-model 绑定,生成的 prop 名将是 arg + “Modifiers”。

<MyComponent v-model:title.capitalize="myText">

相应的声明应该是:

export default {props: ['title', 'titleModifiers'],emits: ['update:title'],created() {console.log(this.titleModifiers) // { capitalize: true }}
}

示例

Test.vue

<template><!-- 5. v-model的修饰符 --><MyComponent v-model.capitalize="myText" /></template><script lang="ts" setup>import { ref,reactive } from 'vue'import MyComponent from '@/views/test/MyComponent.vue';const myText = ref("myText")</script><style lang="scss"></style>

MyComponent.vue

<template><inputtype="text":value="modelValue"@input="handleInput"/>{{ modelValue }}
</template><script lang="ts" setup>const props = defineProps({modelValue: String,modelModifiers: { default: () => ({}) } /* 这个prop可以拿到修饰符 */})console.log(props.modelModifiers) // { capitalize: true }const emit = defineEmits(['update:modelValue'])// 处理input事件function handleInput(e) {let value = e.target.value// 根据是否存在修饰符, 作进一步处理if(props.modelModifiers.capitalize) {value = value.charAt(0).toUpperCase() + value.slice(1)}emit('update:modelValue', value)}</script><style lang="scss"></style>

vue3的v-model相关推荐

  1. 什么是V Model(V模型)

    v-model是一种软件生存期模型,由Paul Rook在1980年率先提出的,在1990年出现在英国国家计算中心的出版物中,旨在提高软件开发的效率和有效性,是我们熟知的瀑布模型的一种改进,瀑布模型( ...

  2. Vue2+Vue3基础知识总结

    Vue3新特性 setup() 新的配置项,值为一个函数,用于配置组件中所用到的所有数据.方法.若返回一个对象,则对象中的属性.方法在模板中均可以直接使用:若返回一个渲染函数,则可以自定义渲染内容(了 ...

  3. 【全文翻译】ML-Leaks: Model and Data Independent Membership Inference Attacks and Defenses on Machine.....

    ML泄漏:基于机器学习模型的模型和数据无关的成员推理攻击与防御 I. INTRODUCTION II. PRELIMINARIES(准备工作) A. Membership Inference Agai ...

  4. Vue3双向绑定的坑 坑死人了

    1.1 vue 3 的v-model使用原理: <child-comp v-model="msg" /> //可翻译为 <child-comp :modelVal ...

  5. backbone学习总结(二)

    今天来看下backbone的路由控制的功能.其实个人感觉backbone,模块就那么几个,熟悉它的框架结构,以及组成,就差不多. 废话不多说,我们来看看还剩下的功能. 关于路由和历史管理 通过 Bac ...

  6. Backbone学习日记[1]:感性认识

    2019独角兽企业重金招聘Python工程师标准>>> 使用backbone.js的意义是什么呢? Backbone将数据呈现为模型, 你可以创建模型.对模型进行验证和销毁,甚至将它 ...

  7. 七天学会ASP.NET MVC (五)——Layout页面使用和用户角色管理

    系列文章 七天学会ASP.NET MVC (一)--深入理解ASP.NET MVC 七天学会ASP.NET MVC (二)--ASP.NET MVC 数据传递 七天学会ASP.NET MVC (三)- ...

  8. yii 全选 php,yii2中gridview使用技巧小结(四)——全选等批量操作

    在用gridview时,大家都注意到了,列表的开头有现成的复选框,这肯定是批量操作中用到的,今天就来介绍一下,gridview中的批量操作,简直简单的不行,效果图如下: 前端页面只需要改这几个地方即可 ...

  9. 【深度学习】Ivy 开源框架,深度学习大一统时代到来?

    它来了,它带着统一主流深度学习框架的接口来了.最近,有一个开源的框架:IVY,它将几个主流的深度学习框架都做了一个统一的封装,包括 PyTorch.TensorFlow.MXNet.Jax 和 Num ...

  10. ElementUI弹出新增窗口

    新建按钮绑定单击事件,对应的处理函数为handleCreate <el‐button type="primary" class="butT" @click ...

最新文章

  1. 速成班出来的AI人才,老板到底要不要?6位导师告诉你行业真相
  2. 洛谷P1001 A+B Problem
  3. kafka使用_kafka使用Interceptors实现消息端到端跟踪
  4. 创建定制的ASP.NET AJAX非可视化客户端组件
  5. 【Python3爬虫】快就完事了--使用Celery加速你的爬虫
  6. 输入矩阵java_java如何输入一个自定义矩阵
  7. vue-cli3安装遇到的问题,卸载不掉旧版本,导致更新不了
  8. Turkey HSD检验法/W法
  9. html添加好友,人人网怎么加好友 人人网怎么通过数字ID加好友
  10. regedit.exe参数说明
  11. linpack测试工具使用说明
  12. 【JavaWeb从零到一】↣JDBC连接池JDBCTemplate
  13. wamp php 7.0,wamp如何尝鲜php7
  14. 计算机房温湿度,数据中心机房标准的温湿度范围
  15. (最新整理)国内网页设计网站网址大全(转)
  16. 微信小程序 用户登录界面,用户名无法切换输入法问题解决方法
  17. 【JavaSE】逻辑控制
  18. 现代信号处理——平稳随机信号通过线性系统
  19. 计算机里的le是什么符号,在python中传递le或ge符号
  20. Zamzar - 免费在线文件格式转换器

热门文章

  1. linux jdk1.7 下载
  2. 使用word批量将.docx(或者.doc)转成.pdf
  3. 是德示波器软件,Keysight示波器上位机软件NS-Scope
  4. 使用c语言求一元二次方程的根
  5. 大学生实用「自学网站/学习资料」,老学长含泪分享!
  6. #BDA#笔记#业务知识:基础商业常识
  7. 天津大学微型计算机控制,天津大学控制工程.doc
  8. Android实时模糊
  9. UG10.0三四五轴零件模具拆电极编程加工全套视频教程
  10. 【实践】PPT制作从入门到精通(含素材资源大全)