Vue 2 和 Vue 3 中实现组件之间自定义组件双向绑定

发布于:2025-07-04 ⋅ 阅读:(20) ⋅ 点赞:(0)

一、Vue 2 中的实现

1. 使用 v-model(默认 value + input
子组件 CustomInput.vue

<template>
  <input v-model="internalValue" />
</template>

<script>
export default {
  props: ['value'], // Vue 2 的 v-model 默认 prop 是 value
  computed: {
    internalValue: {
      get() {
        return this.value;
      },
      set(val) {
        this.$emit('input', val); // Vue 2 的默认事件是 input
      }
    }
  }
}
</script>

 父组件 

<template>
  <CustomInput v-model="message" />
  <p>父组件数据:{{ message }}</p>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello Vue 2!'
    }
  }
}
</script>
2. 使用 .sync 修饰符(多属性双向绑定)
子组件
<template>
  <input v-model="internalTitle" v-model="internalNums"/>
</template>

<script>
export default {
  props: ['title','nums'], // 接收父组件传递的 title
  computed: {
    internalTitle: {
      get() {
        return this.title;
      },
      set(val) {
        this.$emit('update:title', val); // 触发 update:title 事件
      }
    },
    internalNums: {
      get() {
        return this.nums;
      },
      set(val) {
        this.$emit('update:nums', val); // 触发 update:nums 事件
      }
    }
  }
}
</script>
父组件
<template>
  <CustomInput :title.sync="pageTitle" :nums.sync="pageNums"/>
  <p>当前标题:{{ pageTitle }}</p>
  <p>当前nums:{{ pageNums }}</p>
</template>

<script>
export default {
  data() {
    return {
      pageTitle: '默认标题',
      pageNums:'默认Nums',
    }
  }
}
</script>

二、Vue 3 中的实现

1. 默认 v-modelmodelValue + update:modelValue
子组件 CustomInput.vue
<script>
export default {
  props: ['modelValue'], // Vue 3 的 v-model 默认 prop
  emits: ['update:modelValue'], // 显式声明事件
  computed: {
    value: {
      get() {
        return this.modelValue;
      },
      set(val) {
        this.$emit('update:modelValue', val);
      }
    }
  }
}
</script>

<template>
  <input v-model="value" />
</template>
父组件
<template>
  <CustomInput v-model="message" />
  <p>父组件数据:{{ message }}</p>
</template>

<script setup>
import { ref } from 'vue';
const message = ref('Hello Vue 3!');
</script>
2. 多 v-model 绑定(如 v-model:title
子组件

<template>
  <input v-model="internalTitle" v-model="internalNums" />
</template>

<script>
export default {
  props: ['title'],
  emits: ['update:title','update:nums'],
  computed: {
    internalTitle: {
      get() {
        return this.title;
      },
      set(val) {
        this.$emit('update:title', val);
      }
    },
    internalNums: {
      get() {
        return this.nums;
      },
      set(val) {
        this.$emit('update:nums', val);
      }
    }
  }
}
</script>
父组件
<template>
  <CustomInput v-model:title="pageTitle" v-model:nums="pageNums"/>
  <p>当前标题:{{ pageTitle }}</p>
  <p>当前标题:{{ pageNums }}</p>
</template>

<script setup>
import { ref } from 'vue';
const pageTitle = ref('默认title');
const pageNums = ref('默认nums');

</script>

三、关键区别总结

特性 Vue 2 Vue 3
默认 prop 名 value modelValue
默认事件名 input update:modelValue
多属性双向绑定 需用 .sync 修饰符 直接 v-model:arg(如 v-model:title
事件声明 无 emits 选项 需显式声明 emits
Composition API 不支持 <script setup> 支持 <script setup> 简化写法

四、通用最佳实践

  1. 始终通过 $emit 更新数据
    禁止在子组件中直接修改 prop(违反单向数据流)。

  2. 复杂数据验证
    在计算属性的 setter 中添加校验逻辑:

    set(val) {
      if (val.length <= 100) { // 示例:输入长度限制
        this.$emit('update:modelValue', val);
      }
    }
  3. TypeScript 增强(Vue 3)

    <script setup lang="ts">
    const props = defineProps<{ modelValue: string }>();
    const emit = defineEmits<{ (e: 'update:modelValue', value: string): void }>();
    
    const value = computed({
      get: () => props.modelValue,
      set: (val) => emit('update:modelValue', val)
    });
    </script>

五、常见问题

Q:为什么 Vue 3 改用 modelValue
  • 答案:避免与原生 HTML 元素的 value 属性冲突,同时支持多 v-model 绑定。

Q:Vue 2 能兼容 Vue 3 的写法吗?
  • 答案:部分兼容(Vue 2.7+ 支持 emits 声明但不强制),但默认行为仍需遵循 Vue 2 规则。


通过以上对比,你可以根据项目使用的 Vue 版本选择对应的实现方式。如果需要更复杂的场景(如防抖、格式化),可以在计算属性的 setter 中扩展逻辑。


网站公告

今日签到

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