一文搞懂组件上的v-model(含Vue3.4最新用法)

870 阅读2分钟

序言

只要二次封装组件必然少不了v-model进行双向数据传递,本文只介绍常用写法,不讲八股文。只需一文,让你的v-model炉火纯青。(3.4的宏真的很方便!)

一、使用计算属性(Vue3.4之前)

1.传递单值或多值

防止有少部分人不知道,特意强调下:v-model是可以写多个的。后续不再举例多个的用法

<!--父组件-->
<template>
  <ChildComponent v-model="message1" v-model:title="message2"/>
</template>

<script setup>
import { ref } from 'vue';
const message1 = ref('');
const message2 = ref('');
</script>

<!--子组件-->
<template>
  <input v-model="childMsg1" v-model:title="childMsg2"/>
</template>

<script setup>
import { ref, computed } from 'vue';

const props = defineProps({
  message1: String,
  message2: String
});
const emit = defineEmits(['update:modelValue','update:title']);

const childMsg1 = computed({
  get() {
    return props.message1;
  },
  set(val) {
    emit("update:modelValue", val);
  }
});

const childMsg2 = computed({
  get() {
    return props.message2;
  },
  set(val) {
    emit("update:title", val);
  }
});

</script>

2.传递对象

<!--父组件-->
<template>
  <ChildComponent v-model="obj"/>
</template>

<script setup>
import { ref } from 'vue';
const obj = ref({
    foo: '',
    bar: ''
});

</script>

<!--子组件-->
<template>
  <input v-model="childFoo" />
  <input v-model="childBar" />
</template>

<script setup>
import { ref, computed } from 'vue';

const props = defineProps({
  obj: Object
});
const emit = defineEmits(['update:modelValue']);

const childFoo = computed({
  get() {
    return props.obj;
  },
  set(val) {
    emit("update:modelValue", {
        ...props.obj,
        val
    });
  }
});

const childBar = computed({
  get() {
    return props.obj;
  },
  set(val) {
    emit("update:modelValue", {
        ...props.obj,
        val
    });
  }
});

</script>

二、使用侦听器(Vue3.4之前)

1.传递单值或多值

<!--父组件-->
<template>
  <ChildComponent v-model="message" />
</template>

<script setup>
import { ref } from 'vue';
const message = ref('');
</script>

<!--子组件-->
<template>
  <input v-model="childMsg" />
</template>

<script setup>
import { ref, watch } from 'vue';

const props = defineProps({
  message: String
});
const emit = defineEmits(['update:modelValue']);

const childMsg = ref(props.message);
watch(childMsg, val => {
   emit("update:modelValue", val);
});
</script>

2.传递对象

<!--父组件-->
<template>
  <ChildComponent v-model="obj"/>
</template>

<script setup>
import { ref } from 'vue';
const obj = ref({
    foo: '',
    bar: ''
});

</script>

<!--子组件-->
<template>
  <input v-model="childFoo" />
  <input v-model="childBar" />
</template>

<script setup>
import { ref, watch, watchEffect } from 'vue';

const props = defineProps({
  obj: Object
});
const emit = defineEmits(['update:modelValue']);

const childFoo = ref(props.obj.foo);
const childBar = ref(props.obj.bar);
watchEffect(() => {
  emit("update:modelValue", {
    foo: childFoo.value,
    bar: childBar.value
  });
});
</script>

三、defineModel宏(Vue3.4之后)

从 Vue 3.4 开始,推荐的实现方式是使用 defineModel() 宏。 官网机票

1.传递单值

<!--父组件-->
<template>
  <ChildComponent v-model="message" />
</template>

<script setup>
import { ref } from 'vue';
const message = ref('');
</script>

<!--子组件-->
<template>
  <input v-model="childMsg" />
</template>

<script setup>
const childMsg = defineModel()
</script>

是的你没看错,子组件就是如此简单,无需props无需emits

2.传递多值

<!--子组件-->
<template>
  <input v-model="childMsg1" />
  <input v-model="childMsg2" />
</template>

<script setup>
const childMsg1 = defineModel()
const childMsg2 = defineModel('title')
</script>

3.传递对象

<!--子组件-->
<template>
  <input v-model="obj.foo" />
  <input v-model="obj.bar" />
</template>

<script setup>
const obj = defineModel()
</script>

总结

目前开发中还没有遇见过必须要将v-model拆成@input和:value的场景,所以父子组件都直接使用的v-model真的很方便。Vue3.4的宏更方便!建议大家升级。

如果对你有帮助,感谢点赞、收藏、关注