Vue基础--Vue中的双向绑定v-model指令

2023-11-01

一、v-model的作用和使用场景

1.1 v-model指令介绍

  • 期望的绑定值类型:根据表单输入元素或组件输出的值而变化

  • 可以下下面元素使用:

    • <input>
    • <select>
    • <testarea>
    • components
    • <checkbox>
    • <radio>
    • <select>

    表单输入元素都是可以使用的

  • v-model支持的修饰符:

    • .lazy——监听 change 事件而不是 input
    • .number ——将输入的合法符串转为数字
    • .trim—移除输入内容两端空格

1.2 v-model指令的作用

在表单输入元素或组件上创建双向绑定。

它会根据控件类型自动选取正确的方法来更新元素。

它负责监听用户的输入事件来更新数据,并在某种极端场景下进行一些特殊处理。

毕竟表单提交是开发中非常常见的功能,也是和用户交互的重要手段。

用户在登录、注册时需要提交账号密码,检索、新建、更新数据时,需要提交数据,这些都离不开表单提交。

1.3 什么是双向绑定

Vue中的的双向数据绑定是指model模型(Vuedata下定义的变量)和view(视图)的双向绑定。

其中一个发生改变,另一个也会更新改变。

但是更通俗和常用的讲就是当表单元素的值发生变化时。和它绑定的Vue中的data变量也发生改变。,

二、v-model的基本使用

2.1 代码示例和解析

<div id="app">

    <!-- 1.使用v-model实现input的双向绑定 -->
    <input type="text" v-model="message">
 	<h2>input: {{message}}</h2>
    <hr>
    
    <!-- 2.使用v-model实现textarea的双向绑定 -->
    <textarea cols="30" rows="10" v-model="content"></textarea>
    <h2>textarea: {{content}}</h2>
    <hr>
    
    <!-- 3.使用v-model实现checkbox的双向绑定 -->
    <!-- 3.1 checkbox单选框: 绑定到属性中的值是一个Boolean -->
    <!-- label的作用是点击label中的文本时,相当于点击到绑定的input元素 -->
    <label for="agree">
        <input id="agree" type="checkbox" v-model="isAgree"> 同意协议
    </label>
    <h2>checkbox单选: {{isAgree}}</h2>
    <hr>
    
    <!-- 3.2 checkbox多选框: 绑定到属性中的值是一个Array -->
    <!--  checkbox单选框; 绑定到属性中的值是单选框的value -->
    <div class="hobbies">
        <h2>请选择你的爱好:</h2>
        <label for="sing">
            <input id="sing" type="checkbox" v-model="hobbies" value="sing"></label>
        <label for="jump">
            <input id="jump" type="checkbox" v-model="hobbies" value="jump"></label>
        <h2>爱好: {{hobbies}}</h2>
    </div>
    <hr>
    
    
    <!-- 4.使用v-model实现radio的双向绑定 -->
    <!-- radio单选框: 绑定到属性中的值是单选框的value -->
    <div class="gender">
        <label for="male">
            <input id="male" type="radio" v-model="gender" value="male"></label>
        <label for="female">
            <input id="female" type="radio" v-model="gender" value="female"></label>
        <h2>性别: {{gender}}</h2>
    </div>
    <hr>
    
    
    <!-- 4.使用v-model实现select的双向绑定 -->
 	<!-- 4.1 select单选框的值绑定 -->
    <select v-model="fruit">
        <option v-for="item in allFruits" :key="item.value" :value="item.value">
            {{item.text}}
        </option>
    </select>
    <h2>单选: {{fruit}}</h2>
	<!-- 4.2 select多选框的值绑定 -->
    <select multiple size="3" v-model="fruits">
        <option v-for="item in allFruits" :key="item.value" :value="item.value">
            {{item.text}}
        </option>
    </select>
    <h2>多选: {{fruits}}</h2>
    <hr>
</div>

<script src="../lib/vue.js"></script>
<script>
    // 1.创建app
    const app = Vue.createApp({
        data() {
            return {
                message: "Hello Model",		//v-model绑定的input数据
                content: "",				//v-model绑定的textarea数据
                isAgree: false,				//v-model绑定的checkbox单选框数据 
                hobbies: []					//v-model绑定的checkbox多选框数据
                gender: "female"			//v-model绑定的radio单选框数据
                fruit: "orange",			//v-model绑定的select单选框数据
                fruits: [],					//v-model绑定的select多选框数据
                             
                allFruits: [
                    { value: "apple", text: "苹果" },
                    { value: "orange", text: "橘子" },
                    { value: "banana", text: "香蕉" },
                ],						 	// 水果
            }
        }
    })

    // 2.挂载app
    app.mount("#app")
</script>

可以看到,使用v-model的方式非常简单:

  • 在支持v-model的表单输入元素上加上v-model指令
  • Vuedata选项API中定义数据变量,赋值给v-model就实现了数据的双向绑定

这些也都是对基础的表单元素进行操作。实际开发大多会使用各种各样的组件库开发。

但是使用的方式和原理都是一样的。

2.2 v-model和值绑定:

所谓值绑定,其实并不是很高深的东西,只是Vue官方提供的一个概念。

意思就是表单元素中的value值并不是写死的,而是来自于服务器或者配置文件。

我们就可以先将值请求下来,绑定到data返回的对象中,

再使用条件渲染指令和列表渲染指令把值动态绑定到表单元素上,最后通过v-bind指令来进行绑定。

这个过程就是值绑定

例如上面代码中select的绑定方式:

<div id="app"> 
 	<!-- select单选框的值绑定 -->
    <select v-model="fruit">
        <option v-for="item in allFruits" :key="item.value" :value="item.value">
            {{item.text}}
        </option>
    </select>
    <h2>单选: {{fruit}}</h2>

</div>

<script src="../lib/vue.js"></script>
<script>
    // 1.创建app
    const app = Vue.createApp({
        data() {
            return {
                fruit: "orange",			//v-model绑定的select单选框数据      
                allFruits: [
                    { value: "apple", text: "苹果" },
                    { value: "orange", text: "橘子" },
                    { value: "banana", text: "香蕉" },
                ],						 	// 水果
            }
        }
    })

    // 2.挂载app
    app.mount("#app")
</script>

在这段代码中,<select><option>的值并不是直接写死在表单元素上的。

它们的值来自allFruits数组,这个数组可能来自于服务器或者配置文件。

这也是开发中常见的情况。

三、v-model的修饰符

3.1 v-model支持的修饰符:

  • .lazy ——监听 change 事件而不是 input

    • 默认情况下,v-model在进行双向绑定时,绑定的是input事件。

      那么会在每次内容输入后就将最新的值和绑定的属性进行同步。

    • 如果在v-model后跟上lazy修饰符,那么会将绑定的事件切换为 change 事件。

      只有在提交(或者回车)时才会触发。

  • .number ——将输入的合法符串转为数字

  • .trim ——移除输入内容两端空格

3.2 代码示例

<div id="app">
    <!-- 1.lazy: 绑定change事件  -->
    <input type="text" v-model.lazy="message">
    <h2>message: {{message}}</h2>
    <hr>

    <!-- 2.number: 自动将内容转换成数字 -->
    <!-- 
		这里有个冷知识:
		vue2.x中 如果input中输入的是数字,v-model也会自动把数字转为字符串,除非加上.number修饰符
		vue2.x中 如果input中输入的是数字,将可以直接获取到数字,而不用再加.number修饰符
	-->
    <input type="text" v-model.number="counter">
    <h2>counter:{{counter}}-{{typeof counter}}</h2>

    <input type="number" v-model="counter2">
    <h2>counter2:{{counter2}}-{{typeof counter2}}</h2>
    <hr>

    <!-- 3.trim: 去除收尾的空格 -->
    <input type="text" v-model.trim="content">
    <h2>content: {{content}}</h2>
    <hr>

    <!-- 4.使用多个修饰符 -->
    <input type="text" v-model.lazy.trim="content">
    <h2>content: {{content}}</h2>
</div>

<script src="../lib/vue.js"></script>
<script>
    // 1.创建app
    const app = Vue.createApp({
        // data: option api
        data() {
            return {
                message: "Hello Vue",
                counter: 0,
                counter2: 0,
                content: ""
            }
        },
        watch: {
            content(newValue) {
                console.log("content:", newValue)
            }
        }
    })

    // 2.挂载app
    app.mount("#app")
</script>

四、手写v-model原理

官方文档中有提到,v-model的原理其实是背后有两个操作:

  • v-bind绑定value属性的值

  • v-on绑定input事件监听到函数中,函数会获取最新的值赋值到绑定的属性中

依旧上面的原理,可以手写一个v-model的实现:

<div id="app">
    <!-- 
		手动的实现双向绑定:
			先使用v-bind语法糖把message绑定到input的value上
			再使用v-on语法糖绑定input元素的input事件
	-->
    <input type="text" :value="message" @input="change">
</div>

<script src="../lib/vue.js"></script>
<script>
    // 1.创建app
    const app = Vue.createApp({
        data() {
            return {
                message: "Hello Model"
            }
        },
        methods: {
            change(event) {
                // 获取当前input表单元素中的内容
                this.message = event.target.value
            }
        }
    })

    // 2.挂载app
    app.mount("#app")
</script>

至于如果程序中的message发送变化,Vue会有另一部分代码监听数据的变化,并把变化的数据渲染到视图上。

再结合v-model就完成了Vue中数据的双向绑定。

五、v-model用于组件上

5.1 v-model在组件上的基本使用

通过上面的说明可以知道,表单元素上的v-model使用方式如下:

<input v-model="searchText" />

上面的代码其实等价于下面这段 (编译器会对 v-model 进行展开):

<input
  :value="searchText"
  @input="searchText = $event.target.value"
/>

而当使用在一个组件上时,v-model 会被展开为如下的形式:

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

因此<CustomInput> 组件内部需要做两件事:

  • 将内部原生 input 元素的 value属性绑定到 modelValueprop组件上

  • 输入新的值时在 input 元素上触发 update:modelValue 事件

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

<script>
export default {
  props: ['modelValue'],
  emits: ['update:modelValue']
}
</script>


5.2 自定义组件中处理v-model 的参数

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

我们可以通过给 v-model 指定一个参数来更改这些名字。

<MyComponent v-model:title="bookTitle" />

此时子组件应声明一个 title prop,并通过触发 update:title 事件更新父组件值:

<!-- MyComponent.vue -->
<template>
  <input
    type="text"
    :value="title"
    @input="$emit('update:title', $event.target.value)"
  />
</template>

<script>
export default {
  props: ['title'],
  emits: ['update:title']
}
</script>

5.3 自定义组件中处理多个v-model 绑定

我们可以在一个组件上创建多个 v-model 双向绑定,每一个 v-model 都会同步不同的prop

<UserName
  v-model:first-name="first"
  v-model:last-name="last"
/>
<script>
export default {
  props: {
    firstName: String,
    lastName: String
  },
  emits: ['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>

5.4 自定义组件中处理 v-model 修饰符

v-model 有一些内置的修饰符。例如 .trim.number.lazy

在某些场景下,你可能想要一个自定义组件的 v-model 支持自定义的修饰符。

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

<MyComponent v-model.capitalize="myText" />

组件的 v-model 上所添加的修饰符,可以通过 modelModifiers prop 在组件内访问到。

在下面的组件中,声明了 modelModifiers 这个 prop,它的默认值是一个空对象:

<script>
export default {
  props: {
    modelValue: String,
    modelModifiers: {
      default: () => ({})
    }
  },
  emits: ['update:modelValue'],
  created() {
    console.log(this.modelModifiers) // { capitalize: true }
  }
}
</script>

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

注意

组件prop中的 modelModifiers的 包含了 capitalize 且其值为 true

因为它在模板中的 v-model 绑定上被使用了。

有了 modelModifiers 这个 prop,我们就可以在原生事件侦听函数中检查它的值。

然后决定触发的自定义事件中要向父组件传递什么值。

<script>
export default {
  props: {
    modelValue: String,
    modelModifiers: {
      default: () => ({})
    }
  },
  emits: ['update:modelValue'],
  methods: {
    emitValue(e) {
      let value = e.target.value
      // 如果有capitalize的值为true,则做一些对应的操作
      if (this.modelModifiers.capitalize) {
        value = value.charAt(0).toUpperCase() + value.slice(1)
      }
      this.$emit('update:modelValue', value)
    }
  }
}
</script>

<template>
  <input type="text" :value="modelValue" @input="emitValue" />
</template>

对于又有参数又有修饰符的 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 }
  }
}

六、v-model官方文档

https://cn.vuejs.org/api/built-in-directives.html#v-model
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Vue基础--Vue中的双向绑定v-model指令 的相关文章

随机推荐

  • 【驱动器未格式化】怎么修复,【驱动器未格式化】恢复方案

    将闪盘插入电脑的时候为什么会出现 驱动器未格式化 的提示框呢 遇到这个问题时又该怎么处理呢 别慌 下面小编就来给大家演示一下子解决 驱动器未格式化 这个问题的解决方法 工具 软件 sayRecy 步骤1 先百度搜索并下载工具运行后 选中需要
  • LaTex笔记(随时更新)

    文件开头 此开头指定了文档类型 为latex必备 article就不错 中英都很方便 documentclass article 中文支持 latex默认不支持中文 需要引入此包 另将编译器设置为XeLaTeX即可完美支持中文 以下两个包择
  • MySQL数据库安装教程

    目录 安装包下载 安装 安装包下载 直接进入官网下载安装包https dev mysql com downloads windows installer 点击download后出现如下情况选择No thanks just start my
  • 【Intel® RealSense™ SDK 2.0 】在【Linux】环境配置记录

    Intel RealSense SDK 2 0 在 Linux 环境配置记录 Intel RealSense SDK 2 0 官网 系统环境 ubuntu 18 04 建conda环境 conda create n real sense p
  • C语言实现移位密码体制

    问题描述 输入密钥K的值 加密算法 e x x k mod 26 即当前明文字母顺序 如A为1 加上K值之后对应的字母即为密文 解密算法 d y y k mod 26 与加密相反 解密是当前密文字母顺序减去K值对应的字母即为明文 26即26
  • python变量,数据类型,运算符

    这里写自定义目录标题 1 变量 python的变量不需要声明 变量在被使用前必须赋值 变量被赋值后才会被创建 变量赋值和其他语言一样 通过 赋值 例如 usr bin python3 a 1 整型变量 b 1 0 浮点型变量 cc my 字
  • R语言:常用apply函数(apply,tapply,sapply,lapply)用法介绍

    apply函数 对矩阵 数据框 数组 二维 多维 等矩阵型数据 按行或列应用函数FUN进行循环计算 并以返回计算结果 apply X MARGIN FUN X 数组 矩阵 数据框等矩阵型数据 MARGIN 按行计算或按按列计算 1表示按行
  • VsCode 下如何安装shader glsl开发环境

    1 2 安装后搜索glsl canvas 3 glsl linter 能判断语法是否错误的扩展插件 之后去https github com KhronosGroup glslang releases下载glslang 4 文件 首选项 用户
  • [LeetCode] Invert Binary Tree - 二叉树翻转系列问题

    目录 1 Invert Binary Tree 二叉树翻转 递归 题目概述 Invert a binary tree 4 2 7 1 3 6 9 to 4 7 2 9 6 3 1 Trivia This problem was inspir
  • Android依赖剔除和冲突解决

    剔除依赖 模块下build gradle 1 通过包名 模块名剔除 configurations all all exclude group com google guava module guava 2 通过包名剔除 configurat
  • 中小型企业网络组网与配置

    某企业拥有多个部门 如财务部 研发部 技术部等 每个部门使用的 IP 地址网段各不相同 为了便于管理 现需要将同一种部门的业务划分到同一 VLAN 中 不同类型的部门划分到不同 VLAN 中 二层交换原理 二层交换是指数据帧在数据流链路层的
  • C++中stack用法

    c stl栈容器stack用法介绍 stack堆栈容器 堆栈是一个线性表 插入和删除只在表的一端进行 这一端称为栈顶 Stack Top 另一端则为栈底 Stack Bottom 堆栈的元素插入称为入栈 元素的删除称为出栈 由于元素的入栈和
  • (科普)nlp-图解Attention+Transformer

    看文之前 容我多说句 写出来这篇文的作者们 牛逼轰轰 看不懂的好像懂了点什么 看得懂的好像又懂了什么 十万万个点赞 图解Attention seq2seq模型 NLP常用于生成任务的seq2seq结构 如 机器翻译 文本摘要 图像描述生成
  • java学习从入门到进阶的四个阶段送给迷茫的你

    写这篇总结 主要是记录下自己的学习经历 算是自己对知识的一个回顾 也给想要学习 Java 的提供一些参考 对于一些想要学习Java 又不知道从哪里下手 以及现在有哪些主流的 Java 技术 想必大家学习一门技术 前期都很想看到一些结果或成就
  • docker搭建rocketmq集群

    借鉴于 https www cnblogs com qdhxhz p 11096682 html 但是其中有一些错误 本人进行了修改 docker compose yml version 3 5 services rmqnamesrv a
  • RTX3060下双系统安装Ubuntu22.04并配置显卡驱动(超简单)、安装cuda12.1

    首先准备一个启动盘 准备具体步骤在此省略 在windows下准备一块未分区的磁盘空间 插入U盘重启电脑 在重启过程中一直按DEL键 不同电脑按键不同 进入BIOS界面 直接选择U盘空间 点击continue等待 其他的不用管 只需要点两下
  • JDK编译时出现乱码问题(以JDK8(1.8)和JDK17为例)

    先看代码 写个最简单的HelloWorld public class HelloWorld public static void main String args System out println Hello World System
  • 42个Python实用小例子[内附200+代码地址]

    经常有同学苦恼 学了python基础之后找不到合适的练手机会 为此 有位热心人创建了一个项目 搜集整理了一堆实用的python代码小例子 这些小例子包括但不限于 Python基础 Web开发 数据科学 机器学习等方向 短小精炼 力争让你60
  • 深度优先遍历DFS (岛屿问题)java

    算法之深度优先遍历 DFS 最近在学习DFS和BFS 所以做一些学习的笔记 这里是深度遍历 首先 比较常见的深度遍历题目就是网格题 可抽象为二维数组 在LeetCode中常见的是岛屿问题 思想 深度优先遍历的思想可以理解为 找到一个起始点S
  • Vue基础--Vue中的双向绑定v-model指令

    一 v model的作用和使用场景 1 1 v model指令介绍 期望的绑定值类型 根据表单输入元素或组件输出的值而变化 可以下下面元素使用