[vue2/vue3] -- 深入剖析v-model的原理、父子组件双向绑定的多种写法

简介: [vue2/vue3] -- 深入剖析v-model的原理、父子组件双向绑定的多种写法

经典面试题:请阐述一下 v-model 的原理

经典面试题:请说一下vue2与vue3在使用 v-model 时的异同点

经典面试题:请列举 vue2/vue3 的父子组件的数据双向绑定的多种写法

本文即可将上述三个面试题阐述清楚,并提供具体案例来让小伙伴们加深理解、彻底掌握!本文较长,小伙伴们可以先收藏+关注,抽空学习哦~💕


💟 上一篇文章 Vue2中父子组件互相传值和方法调用(热榜前十)

📝 系列专栏 vue从基础到起飞

v-model 可以作用于表单元素,又可作用于自定义组件,无论是哪一种情况(vue2, vue3),它都是一个语法糖,最终会生成一个属性和一个事件

当其作用于表单元素时vue会根据作用的表单元素类型而生成合适的属性和事件。例如:

  • text 和 textarea 元素使用 value property 和 input 事件;
  • checkbox 和 radio 使用 checked property 和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。

v-model用于自定义组件

vue2的情况

v-model也可作用于自定义组件,当其作用于自定义组件时,默认情况下,它会生成一个value属性和input事件。

子组件 HelloWorld.vue

这个子组件只是实现一个简单计数器的功能,然后我向上分发的事件名称是update:value。但是vue2如果使用v-model会自动的把这个事件名称给改成input

<template>
  <div class="hello">
    <button @click="change(value - 1)">-</button>
    <span>{{value}}</span>
    <button @click="change(value + 1)">+</button>
  </div>
</template>
 
<script>
export default {
  name: "HelloWorld",
  props: {
    value: Number,
  },
  methods: {
    change(val) {
      this.$emit("update:value", val);
    },
  },
};
</script>
复制代码
APP.vue 来使用
<HelloWorld :value="inputVal" @update:value="inputVal = $event" />
等效于
<HelloWorld v-model="inputVal" />
复制代码

结果:

分析虚拟dom结果

vue2的虚拟dom查看方式是 在mounted中使用this._vnode来进行查看,然后查看componentOptions来查看组件传递的属性。

开发者可以通过组件的model配置来改变生成的属性和事件,例如:
修改子组件 HelloWorld.vue
<template>
  <div class="hello">
    <button @click="change(number - 1)">-</button>
    <span>{{ number }}</span>
    <button @click="change(number + 1)">+</button>
  </div>
</template>
 
<script>
export default {
  name: "HelloWorld",
  props: {
    number: Number,
  },
  model: {
    prop: "number", // 默认为 value
    event: "change", // 默认为 input
  },
  methods: {
    change(val) {
      this.$emit("change", val);
    },
  },
};
</script>
复制代码
 
父组件修改
<HelloWorld v-model="inputVal" />
<!-- 等效于 -->
<HelloWorld :number="inputVal" @change="data=$event" />
复制代码
效果

vue3的情况

v-model也可作用于自定义组件,当其作用于自定义组件时,默认情况下,它会生成一个modelValue属性和onUpdate:modelValue事件。

子组件 Comp.vue
<script setup>
import { ref, } from 'vue'
 const props =  defineProps({
    modelValue: Number
  })
 
 const emits = defineEmits(['update:modelValue']);
  
  const change = (val) => {
    emits('update:modelValue', val)
  }
</script>
<template>                             
  <button @click="change(props.modelValue -  1)">
    -
  </button>
  <span>{{props.modelValue}}</span>
  <button @click="change(props.modelValue +  1)">
    +
  </button>
</template>
复制代码
父组件App.vue
<script setup>
import { ref, getCurrentInstance } from 'vue'
 import Comp from './Comp.vue'
 
const msg = ref(123);
 const internalInstance = getCurrentInstance();
  console.log(internalInstance)
 
</script>
 
<template>                             
  <Comp v-model="msg"></Comp>
  等效于
  <Comp :modelValue="msg" @update:modelValue="msg = $event"></Comp>
</template>
复制代码
结果
虚拟dom分析

vue3 的查看虚拟dom的使用方式,是使用``getCurrentInstance`来查看, 里面的children中的props中来查看属性传递

区别

vue2和vue3都有v-model,原理都是生成一个属性和一个事件,但是也存在些区别 , 区别如下:

.sync修饰符

vue3中的.sync修饰符是去掉了的,他的功能可以由v-model的参数替代

例如:

<!-- vue2 -->
<Comp :title="inputVal" @update:title="inputVal = $event" />
<!-- 简写为 -->
<Comp :title.sync="inputVal" />
 
<!-- vue3 -->
<Comp :title="inputVal" @update:title="inputVal = $event" />
<!-- 简写为 -->
<Comp v-model:title="inputVal" />
复制代码
多个v-model

vue3中允许你写多个v-model,这也是强烈的说明了,v-model就是一个语法糖,只是帮你减少了代码量,仅此而已。vue2不能写多个v-model

<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />
 
<!-- 是以下的简写: -->
 
<ChildComponent
  :title="pageTitle"
  @update:title="pageTitle = $event"
  :content="pageContent"
  @update:content="pageContent = $event"
/>
复制代码
##v-model 的修饰符不同

vue2.x是自带的修饰符,但是在3.x的版本中,可以自定义修饰符哦 .在3.x中的修饰符会在当作属性传递给子组件,并且在属性中生成一个modelModifiers的属性。存在这个修饰符就会有对应的修饰符,并且是true,如果没有传递,那就是undefined。

示例代码:

修改子组件Comp.vue

<script setup>
import { ref, } from 'vue'
 const props =  defineProps({
    modelValue: Number,
    modelModifiers: { 
      default: () => ({})
    }
  })
 
 const emits = defineEmits(['update:modelValue']);
  
  const change = (val) => {
    // 如果存在修饰符range2,那就多加1,减法就没有效果
    if(props.modelModifiers.range2){
      val ++;
    }
    emits('update:modelValue', val)
  }
</script>
<template>                             
  <button @click="change(props.modelValue -  1)">
    -
  </button>
  <span>{{props.modelValue}}</span>
  <button @click="change(props.modelValue +  1)">
    +
  </button>
</template>
复制代码

父组件使用

复制代码

效果

相关文章
|
JavaScript 前端开发 API
Vue 2 与 Vue 3 的区别:深度对比与迁移指南
Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架,在过去的几年里,Vue 2 一直是前端开发中的重要工具。而 Vue 3 作为其升级版本,带来了许多显著的改进和新特性。在本文中,我们将深入比较 Vue 2 和 Vue 3 的主要区别,帮助开发者更好地理解这两个版本之间的变化,并提供迁移建议。 1. Vue 3 的新特性概述 Vue 3 引入了许多新特性,使得开发体验更加流畅、灵活。以下是 Vue 3 的一些关键改进: 1.1 Composition API Composition API 是 Vue 3 的核心新特性之一。它改变了 Vue 组件的代码结构,使得逻辑组
2406 0
|
JavaScript 前端开发 算法
Vue 3 和 Vue 2 的区别及优点
Vue 3 和 Vue 2 的区别及优点
|
JavaScript 前端开发 UED
vue2和vue3的响应式原理有何不同?
大家好,我是V哥。本文详细对比了Vue 2与Vue 3的响应式原理:Vue 2基于`Object.defineProperty()`,适合小型项目但存在性能瓶颈;Vue 3采用`Proxy`,大幅优化初始化、更新性能及内存占用,更高效稳定。此外,我建议前端开发者关注鸿蒙趋势,2025年将是国产化替代关键期,推荐《鸿蒙 HarmonyOS 开发之路》卷1助你入行。老项目用Vue 2?不妨升级到Vue 3,提升用户体验!关注V哥爱编程,全栈开发轻松上手。
1057 2
|
JavaScript 前端开发 API
管理数据必备;侦听器watch用法详解,vue2与vue3中watch的变化与差异
一篇文章同时搞定Vue2和Vue3的侦听器,是不是很棒?不要忘了Vue3中多了一个可选项watchEffect噢。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
9月前
|
缓存 JavaScript
vue中的keep-alive问题(2)
vue中的keep-alive问题(2)
670 137
|
10月前
|
JavaScript
Vue中如何实现兄弟组件之间的通信
在Vue中,兄弟组件可通过父组件中转、事件总线、Vuex/Pinia或provide/inject实现通信。小型项目推荐父组件中转或事件总线,大型项目建议使用Pinia等状态管理工具,确保数据流清晰可控,避免内存泄漏。
795 2
|
JavaScript 安全
在 Vue 中,如何在回调函数中正确使用 this?
在 Vue 中,如何在回调函数中正确使用 this?
591 0