vue2 Vue3 v-model 原理

Posted twinkle||cll

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue2 Vue3 v-model 原理相关的知识,希望对你有一定的参考价值。

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

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

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

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

用于自定义组件

vue2

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

子组件 HelloWorld

这个子组件只是实现一个简单计数器的功能,然后我向上分发的事件名称是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 来使用

<HelloWorld :value="inputVal" @update:value="inputVal = $event" />
等效于
<HelloWorld v-model="inputVal" />
复制代码

结果:

分析虚拟dom结果

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

开发者可以通过组件的model配置来改变生成的属性和事件 修改子组件 HelloWorld

<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

<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

<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子组件

<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>
复制代码

父组件使用

<Comp v-model.range2="msg"></Comp>
复制代码

效果

vue3测试代码地址: vue2测试代码地址,由于忘记登录,被删除了🤣🤣🤣

以上是关于vue2 Vue3 v-model 原理的主要内容,如果未能解决你的问题,请参考以下文章

vue2 Vue3 v-model 原理

(十二)Vue3.x中重写的v-model

Vue3.0更优雅的使用v-model

Vue2的.sync修饰符转Vue3中v-model

vue2.0和vue3.0中的区别

vue3中的v-model