v-model的使用和原理(超详细,持续更新)

欢迎大家讨论学习


前言

这里主要介绍v-model在表单元素上的使用和原理,摸清原理后,对v-model在组件中的使用有很大帮助,后续会慢慢介绍在组件中的应用

v-model是Vue框架的一个指令,v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。

提示:以下是本篇文章正文内容,下面案例可供参考

一、须知

  1. v-model 会忽略所有表单元素的 value、checked、selected attribute 的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。
  2. v-model 在内部为不同的输入元素使用不同的property 并抛出不同的事件
  • text 和 textarea 元素使用 value property 和 input 事件;
  • radio 和checkbox 使用 checked property 和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。
  1. v-model双向数据绑定的关键(重中之重):
  • 数据---->视图
    通过v-bind: 将属性和响应式数据进行绑定,实现数据改变---->视图改变
  • 视图---->数据
    用户与视图进行交互,会触发相应的事件(v-on:),然后通过事件处理函数将新数据重新更新到属性依赖的响应式数据(其实就是数据的更新),实现视图改变---->数据改变

二、使用及原理

1. text和textarea

text文本
关键代码如下(示例):

<!-- text的使用-->
账户: <input type="text" v-model = "account"> <br><br>
<!-- text的原理 -->
密码: <input type="password" :value="password" @input="password = $event.target.value">

textarea文本域
textarea文本域和text文本的使用和原理一模一样

2. radio 和checkbox

radio单选框
关键代码如下(示例):

<!-- radio的使用-->
<!-- 这里需要我们自己手动添加value,因为我们需要拿到新数据重新更新到属性所绑定的数据 -->
: <input type="radio" name="gender" value="male" v-model="gender">
<!-- radio的原理 -->
: <input type="radio" name="gender" value="female" :checked="gender === 'female'" @change="gender = $event.target.value">

checkbox复选框
(1)单个复选框(绑定到布尔值,不用手动加value

关键代码如下(示例):

<!-- checkbox的使用-->
<input type="checkbox" v-model="agree">阅读并接受《用户协议》
<!-- checkbox的原理 -->
<input type="checkbox" :checked="agree" @change="agree = $event.target.checked">阅读并接受《用户协议》

(2)多个复选框(绑定到同一个数组,用手动加value

关键代码如下(示例):

爱好:
<!-- checkbox的使用-->
吃饭: <input type="checkbox" name="hobby" value="eat" v-model="hobby">
睡觉: <input type="checkbox" name="hobby" value="sleep" v-model="hobby">
<!-- checkbox的原理 -->
打豆豆: <input type="checkbox" name="hobby" value="play" :checked= "hobby.indexOf('play') !== -1" @change="changeHobby">
-------------------------------------------------------
// hobby需要用一个数组来接收 hobby: [],
changeHobby(){
    if (this.hobby.indexOf('play') === -1) {
    	// 没有该项时,change事件后就添加
        this.hobby.push('play')
    } else {
    	// 有该项时,change事件后就删除
        const index = this.hobby.indexOf('play')
        this.hobby.splice(index, 1)
    }
}

3. select

select选择框
关键代码如下(示例):

<!-- select的使用-->
居住地:
<select v-model="city1">
    <option>北京</option>
    <option>上海</option>
    <option>广州</option>
    <option>深圳</option>
</select> <br><br>
<!-- select的原理 -->
籍贯:
<select :value="city2" @change="city2 = $event.target.value">
    <option>北京</option>
    <option>上海</option>
    <option>广州</option>
    <option>深圳</option>
</select> <br><br>

期间用到的data:

data: {
    account: '',
    password: '',
    gender: '',
    hobby: [],
    city1: '北京',
    city2: '上海',
    agree: '',
}

补充

一定一定要好好研读上面“须知”的第三条!!!

看完上述内容,你们可能还会有这样的疑惑: 为什么radio和checkbox在使用的过程中需要手动添加value属性???

我们可以这样理解(超详细):

  1. 根据须知2我们知道,在v-model内部radio和checkbox是使用 checked property 和 change 事件实现的。
  2. 根据须知3我们知道,触发事件后,通过事件处理函数,我们需要拿到新数据,然后重新更新到属性所依赖的响应式数据
  3. 在text/textarea/select中,我们可以通过value拿到新数据来重新更新数据。但是,在radio和checkbox中,我们没办法拿到选中的新数据,这时我们就需要手动设置value值,使得在事件处理函数中可以使用该值。
    而为什么单个复选框不需要手动设置value值???
    这是因为单个复选框绑定的是布尔值,在其事件处理函数中可以拿到新数据,可以做到数据的更新

我们还可以直接这样理解(简略版):
直接看事件处理函数,它想要更新数据,就看它以现有的条件能不能拿到新数据,如果不能就需要手动设置value值,从而拿到新数据,然后进行数据的更新

总结

v-model在表单元素的使用时,我们只需记住:

radio和checkbox(多个复选框)需要手动添加value值。


后续还会更新v-model双向数据绑定在组件中的应用,感谢大家的关注
来了来了,接下来继续给大家介绍一下v-model在组件中的应用

三、v-model在组件中的应用

为了方便表单元素复用,我们通常把表单元素封装成表单类组件
下面介绍v-model在组件中的应用
核心:一个组件上的 v-model 默认会利用名为 value的 属性 和名为 input 的事件

提示:在此之前你应该掌握组件通讯相关知识

实现双向数据绑定的核心:
①父传子:数据应该是父组件props传递过来的,子组件内将v-model拆解绑定数据
②子传父:通过自定义事件,子组件将新值传递给父组件修改

1. 表单类组件封装

先给大家介绍一下不使用v-model时的用法

关键代码如下(示例):

父组件:

<!-- 注意:组件上绑定的事件默认都是自定义事件 -->
<City :cityId="selectId" @changeId="selectId = $event"></City>

子组件:

<!-- 注意:这里不能直接使用v-model实现双向数据绑定,
  因为这里的数据是父组件传递过来的,不能直接修改,所以要将v-model拆解绑定数据 -->
<select :value="cityId" @change="change">
     <option value="1">北京</option>
     <option value="2">上海</option>
     <option value="3">广州</option>
     <option value="4">深圳</option>
</select>
...
// 接收父组件传过来的数据
props:['cityId'],
methods: {
   change(e){
   		// 触发自定义事件
       this.$emit('changeId', e.target.value)
   }
}

2. 使用v-model简化代码

上面的代码可以简化写成这样
父组件:

<City v-model="selectId"></City>
<!-- 上面这段代码等价于下面这段代码 -->
<!-- <City :value="selectId" @input="selectId = $event"></City> -->

子组件:

<select :value="value" @change="change">
     <option value="1">北京</option>
     <option value="2">上海</option>
     <option value="3">广州</option>
     <option value="4">深圳</option>
</select>
...
// 当在组件上使用v-model时,这里的变量名必须是 value
props:['value'],
methods: {
   change(e){
   		// 当在组件上使用v-model时,这里自定义事件的名字必须是 input
       this.$emit('input', e.target.value)
   }
}

拓展
有的小伙伴可能会有这样的想法(错误的):这是不是就是为了凑成v-model拆分出来的属性和事件,那这个自定义事件名可不可以改成change,因为value属性change事件也可以凑成v-model
答案是不能
因为一个组件上的 v-model 默认会利用名为 value 的 属性 和名为 input 的事件(核心)
然而我们知道单选框、复选框等类型的输入控件对于value有不同的目的。
我们可以通过model 选项来修改这种默认情况

以radio单选框为例

父组件:

<Gender v-model="gender"></Gender>
<!-- 上面这段代码等价于下面这段代码 -->
<!-- <Gender :gender="gender" @change="gender= $event"></Gender> -->

子组件:

:<input type="radio" name="性别" value="male" :checked="gender === 'male'" @change="$emit('change',$event.target.value)">
:<input type="radio" name="性别" value="female" :checked="gender === 'female'" @change="$emit('change', $event.target.value)">
...
// 修改v-model的默认 	
// 一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件
model: {
    prop: 'gender',
    event: 'change'
},
props: ['gender']

v-model在表单元素的使用和在组件中的使用原理不同
① 在表单元素上,v-model 在内部为不同的输入元素使用不同的property 并抛出不同的事件
② 在组件上,v-model 默认会利用名为 value的属性和名为input的事件

3. .sync 修饰符

作用:可以实现子组件与父组件数据的双向绑定
特点:prop属性名,可以自定义,非固定为value
本质:就是 :属性名@update:属性名 的合写

父组件:

<Home :homeId.sync="id"></Home>
<!-- 上面这段代码等价于下面这段代码 -->
<!-- <Home :homeId="id" @update:homeId="id = $event"></Home> -->

子组件:

<select :value="homeId" @change="change">
     <option value="1">山东</option>
     <option value="2">山西</option>
     <option value="3">河南</option>
     <option value="4">河北</option>
</select>
...
props:['homeId'],
methods: {
   change(e){
      this.$emit('update:homeId', e.target.value)
   }
},

和v-model相比,.sync修饰符的优点:更加灵活简便
本质都一样:①父传子:数据是父组件props传递过来的 ②子传父:通过自定义事件,子组件将新值传递给父组件修改

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值