v-model

Vue2中的v-model

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

  • 当其作用于表单元素时,vue会根据作用的表单元素类型而生成合适的属性和事件。例如,作用于普通文本框的时候,它会生成value属性和input事件,而当其作用于单选框或多选框时,它会生成checked属性和change事件。

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

<Comp v-model="data" />
<!-- 等效于 -->
<Comp :value="data" @input="data=$event" />

可以通过组件的model配置来改变生成的属性和事件

// Comp
const Comp = {
  model: {
    prop: "number", // 默认为 value
    event: "change" // 默认为 input
  }
  // ...
}
Comp v-model="data" />
<!-- 等效于 -->
<Comp :number="data" @change="data=$event" />

Vue2比较让人诟病的一点就是提供了两种双向绑定:v-model和.sync

<!-- vue2 -->
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
<!-- 简写为 -->
<ChildComponent :title.sync="pageTitle" />

Vue3的变化

为了让v-model更好的针对多个属性进行双向绑定,Vue3作出了以下修改。

  1. 当对自定义组件使用v-model指令时,绑定的属性名由原来的value变为modelValue,事件名由原来的input变为update:modelValue。
<!-- vue2 -->
<ChildComponent :value="pageTitle" @input="pageTitle = $event" />
<!-- 简写为 -->
<ChildComponent v-model="pageTitle" />

<!-- vue3 -->
<ChildComponent
  :modelValue="pageTitle"
  @update:modelValue="pageTitle = $event"
/>
<!-- 简写为 -->
<ChildComponent v-model="pageTitle" />
  1. 去掉了.sync修饰符,它原本的功能由v-model的参数替代
<!-- vue2 -->
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
<!-- 简写为 -->
<ChildComponent :title.sync="pageTitle" />

<!-- vue3 -->
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
<!-- 简写为 -->
<ChildComponent v-model:title="pageTitle" />
  1. model配置被移除

  2. 允许自定义v-model修饰符
    组件内部使用使用props的modelModifiers属性接受自定义修饰符

<template>
  <div>
    <custom-input v-model.hello.word="message"  v-model:msg.sss="message" />
    <p>Message: {{ message }}</p>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import CustomInput from './CustomInput.vue';

const message = ref('ssssssss');
</script>
<!-- CustomInput -->
<template>
  <input :value="modelValue" @input="emit('update:modelValue', $event.target.value)">
</template>

<script setup>
import { defineProps, defineEmits } from 'vue';

const { modelValue, modelModifiers, msg } = defineProps(['modelValue', 'modelModifiers', 'msg']);

console.log(modelValue,msg,modelModifiers); // ssssssss ssssssss {hello: true, word: true}

const emit = defineEmits(['update:modelValue']);
</script>

使用computed拦截v-model

<template>
  <div>
    <custom-input v-model="params" />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import CustomInput from './CustomInput.vue';

const params = ref({
  name: '张三',
  age: 18,
  gender: '男',
});

</script>
<template>
  <form>
    <input v-model="modelRef.name"/>
    <input v-model="modelRef.age" />
    <input v-model="modelRef.gender" />
  </form>
</template>

<script setup>
import {defineEmits,defineProps, computed } from 'vue';
 
const props = defineProps(['modelValue']);

const emit = defineEmits(['update:modelValue']);

// 使用computed拦截v-model
function useVmodel(props, prop, emit) {
  return computed({
    get() {
      return new Proxy(props[prop], {
        get(target, key) {
          // console.log('get', key, target)
          return Reflect.get(target, key)
        },
        set(target, key, value) {
          // console.log('set', key, value)
          emit('update:' + prop, {
            ...target,
            [key]: value
          })
          return true
        }
      })
    },
    set(value) {
      emit('update:'+prop, value)
    }
  })
}

const modelRef = useVmodel(props, 'modelValue', emit)
</script>

<style>
input {
  border: 1px solid #000;
  margin: 20px;
}
</style>
posted @ 2024-03-26 09:27  冰凉小手  阅读(31)  评论(0编辑  收藏  举报