Chapter 17 v-model进阶

发布于:2024-12-06 ⋅ 阅读:(33) ⋅ 点赞:(0)

欢迎大家订阅【Vue2+Vue3】入门到实践 专栏,开启你的 Vue 学习之旅!


1 v-model原理

1. 基本原理

v-model 本质上是一个语法糖,它将 value 属性 和 input 事件 的绑定合并为一个指令。
对于输入框这种常见的表单元素,v-model 会自动为你绑定 value 属性和 input 事件,实现数据双向绑定。

2. 作用
提供数据的双向绑定

  • :value :数据变,视图跟着变
  • @input:视图变,数据跟着变

【示例】

<template>
<div id="app" >
  <input v-model="msg1" type="text">
  <input :value="msg2"  type="text">
</div>
</template>

<script>
export default {
  data(){
    return{
      msg1:'',
      msg2:''
    }

  }

}
</script>

<style>

</style>


【详解】

v-model="msg1"msg1 会和第一个 <input> 元素的 value 进行双向绑定。

  • 当用户在输入框中输入内容时,msg1 会更新为输入的值。
  • 如果 msg1 改变,输入框的值会同步更新。

:value="msg2":第二个 <input> 通过 :value 绑定 msg2,但是它并没有绑定 input 事件。

  • msg2 只是将初始值传递给输入框,但当用户输入新的内容时,msg2 的值不会更新。
  • 如果希望 msg2 随着用户输入动态更新,还需要显式地处理输入事件。

【运行结果】
在这里插入图片描述
在这里插入图片描述
【优化】

<template>
<div id="app" >
  <input v-model="msg1" type="text">
  <!-- 模板中获取事件的形参 -> 通过 $event 获取 -->
  <input :value="msg2" @input="msg2 = $event.target.value"  type="text">
</div>
</template>

:value="msg2" @input="msg2 = $event.target.value":第二个 <input> 不仅绑定了 msg2 的初始值(通过 :value="msg2"),还显式地绑定了 input 事件。

  • 每当用户输入时,@input 事件会触发,并通过 $event.target.value 获取输入框的值。
  • 通过 msg2 = $event.target.value,更新 msg2 的值,从而实现双向绑定。
  • 该方式使得 msg2 的值能够随着用户的输入动态更新。

【运行结果】
在这里插入图片描述

3. 注意事项
v-model 在不同类型的表单元素上工作时,底层的实现机制会有所不同。

  • 文本框 (<input type="text">):绑定 value 属性和 input 事件。
  • 复选框 (<input type="checkbox">):绑定 checked 属性和 change 事件,处理布尔值或数组。
  • 单选框 (<input type="radio">):绑定 checked 属性和 change 事件,处理选中的值。
  • 下拉框 (<select>):绑定 value 属性和 change 事件,处理选中的值。

Vue 会根据表单元素的不同,自动选择合适的属性和事件来实现数据的双向绑定,从而简化了开发者的工作。

2 表单类组件封装

1. 需求目标
实现子组件和父组件数据的双向绑定 。

2. 示例代码

父组件App.vue

<template>
  <div class="app">
    <BaseSelect></BaseSelect>
  </div>
</template>

<script>
import BaseSelect from './components/BaseSelect.vue'
export default {
  data() {
    return {
      selectId: '102',
    }
  },
  components: {
    BaseSelect,
  },
}
</script>

<style>
</style>

子组件BaseSelect.vue

<template>
  <div>
    <select>
      <option value="101">北京</option>
      <option value="102">上海</option>
      <option value="103">武汉</option>
      <option value="104">广州</option>
      <option value="105">深圳</option>
    </select>
  </div>
</template>

<script>
export default {
}
</script>

<style>
</style>

【代码分析】

  • 父组件:定义了一个 selectId,用于存储当前选中的城市 ID,但没有将该值传递给子组件
  • 子组件:<select> 元素的值没有任何绑定,用户在子组件中选中城市时,父组件中的 selectId 不会自动更新

【暴露得问题】
父组件和子组件之间的数据没有双向绑定,修改子组件中的选择不会反映到父组件的数据中。

【优化】
父组件App.vue:

<template>
  <div class="app">
    <BaseSelect
      :cityId="selectId"
      @changeId="selectId=$event"
    ></BaseSelect>
  </div>
</template>

<script>
import BaseSelect from './components/BaseSelect.vue'
export default {
  data() {
    return {
      selectId: '102',
    }
  },
  components: {
    BaseSelect,
  },
}
</script>

<style>
</style>

子组件BaseSelect.vue:

<template>
  <div>
    <select :value="cityId" @change=handleChange>
      <option value="101">北京</option>
      <option value="102">上海</option>
      <option value="103">武汉</option>
      <option value="104">广州</option>
      <option value="105">深圳</option>
    </select>
  </div>
</template>

<script>
export default {
    props:{
        cityId:String
    },methods:{
        handleChange(e){
            this.$emit('changeId',e.target.value)
        }

    }

}
</script>

<style>
</style>

【优化思路】
在这里插入图片描述
在这里插入图片描述
手动实现双向绑定:

  • 父组件:selectId 被传递给子组件 BaseSelect,并通过 @changeId 监听子组件发出的 changeId 事件,将子组件的选中值($event) 更新到父组件的 selectId 上。
  • 子组件:子组件通过 props 接收来自父组件的 cityId,并将 select 元素的 value 属性与其绑定,用户选择城市时,触发 @change 事件,使用 this.$emit('changeId', e.target.value) 将选中的值传递回父组件。

【运行结果】
在这里插入图片描述
在这里插入图片描述

  • 实现了父子组件之间的数据双向绑定。
  • 当用户在子组件中选择不同的城市时,selectId 会自动更新。
  • 如果 selectId 在父组件中发生变化,子组件的选择框也会同步更新。

3 v-model简化代码

1. 目标

父组件通过 v-model 简化代码,实现子组件和父组件数据 双向绑定

2. 简化思路

v-model 其实就是 :value@input 事件的简写

  • 子组件:props 通过 value 接收数据,事件触发 input
  • 父组件:v-model 直接绑定数据

在这里插入图片描述

3. 示例代码

父组件App.vue

<template>
  <div class="app">
    <!-- v-mdel= :value +@input-->
    <BaseSelect
      v-model="selectId"
    ></BaseSelect>
  </div>
</template>

<script>
import BaseSelect from './components/BaseSelect.vue'
export default {
  data() {
    return {
      selectId: '102',
    }
  },
  components: {
    BaseSelect,
  },
}
</script>

<style>
</style>

子组件BaseSelect.vue

<template>
  <div>
    <select :value="value" @change=handleChange>
      <option value="101">北京</option>
      <option value="102">上海</option>
      <option value="103">武汉</option>
      <option value="104">广州</option>
      <option value="105">深圳</option>
    </select>
  </div>
</template>

<script>
export default {
    props:{
        value:String
    },methods:{
        handleChange(e){
            this.$emit('input',e.target.value)
        }

    }

}
</script>

<style>
</style>

使用 v-model 实现双向绑定:

  • 父组件:通过 v-model="selectId"selectId 绑定到子组件的 value 上。
    子组件:接收一个名为 valueprop,并使用 :value="value" 来将父组件的 selectId 传递给 <select> 元素。当选择发生变化时,子组件会触发 input 事件,父组件通过 v-model 自动接收更新后的值。

【运行结果】
在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到