当前位置: 首页 > news >正文

Vue2-3 优雅的在子组件修改父组件传递过来的v-model

 在子组件修改父组件传递过来的v-model,这样会破坏单向数据流,造成屎山代码,为了避免这个问题,需要给一个中间层来相对舒服的使用v-model。方法就是用computed去拦截v-model,然后在computed 里面去触发 emit 事件来修改父组件传来的v-model

以下是Vue 3.4 之前版本的做法


核心实现逻辑

  1. 子组件接收 v-model
    默认绑定 modelValue 属性,通过 defineProps 接收父组件传递的值。
  2. 定义 emit 事件
    使用 defineEmits 声明 update:modelValue 事件用于更新父组件数据。
  3. 通过 computed 拦截
    使用 computed 的 get/set 方法,在 set 中触发 emit 回传数据。

二、基础示例代码

父组件
<template>
  <ChildComponent v-model="message" />
</template>
 
<script setup>
import { ref } from 'vue';
const message = ref('Hello');
</script>

子组件

<template>
  <input v-model="proxyValue" />
</template>
 
<script setup>
import { computed } from 'vue';
 
const props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);
 
// 核心:通过 computed 拦截 
const proxyValue = computed({
  get: () => props.modelValue, 
  set: (newValue) => {
    emit('update:modelValue', newValue); // 触发父组件更新 
  }
});
</script>

三、处理对象类型 v-model

若父组件传递对象,需为每个属性单独拦截:

父组件
<template>
  <ChildComponent v-model="form" />
</template>
 
<script setup>
import { reactive } from 'vue';
const form = reactive({ name: 'Alice', age: 25 });
</script>
子组件
<template>
  <input v-model="nameProxy" />
  <input v-model="ageProxy" />
</template>
 
<script setup>
import { computed } from 'vue';
 
const props = defineProps({ modelValue: Object });
const emit = defineEmits(['update:modelValue']);
 
// 拦截对象属性 
const nameProxy = computed({
  get: () => props.modelValue.name, 
  set: (val) => {
    emit('update:modelValue', { ...props.modelValue,  name: val });
  }
});
 
const ageProxy = computed({
  get: () => props.modelValue.age, 
  set: (val) => {
    emit('update:modelValue', { ...props.modelValue,  age: val });
  }
});
</script>

以下是 Vue 3.4 的做法


在 Vue3.4 及以上版本中,官方新增的 defineModel 宏可以大幅简化 v-model 的双向绑定逻辑,完全替代之前基于 computed + emit 的拦截方案。以下是改写方法和对比分析:

一、用 defineModel 改写原方案的核心优势

  1. 代码简化
    无需手动声明 props 和 emitdefineModel 自动处理 modelValue 和 update:modelValue 的逻辑12。
  2. 原生支持响应式
    直接返回一个 ref 对象,无需通过 computed 的 get/set 手动触发更新。
  3. 兼容修饰符
    支持 v-model 的内置修饰符(如 .trim)和自定义修饰符,可自动处理值转换逻辑。

二、基础示例对比 

新方案(基于 defineModel 

<!-- 子组件 -->
<script setup>
const model = defineModel(); // 自动处理 prop 和 emit 
</script>
 
<template>
  <input v-model="model" />
</template>

三、进阶用法

1. 多 v-model 绑定 

父组件: 

<ChildComponent v-model:name="name" v-model:age="age" />

子组件:

<script setup>
const nameModel = defineModel('name');
const ageModel = defineModel('age');
</script>

2. 类型校验与默认值 

<script setup>
const model = defineModel({
  type: String,
  default: '默认值'
});
</script>
3. 自定义修饰符

父组件:

<ChildComponent v-model.uppercase="text"  />

子组件: 

<script setup>
const [model, modifiers] = defineModel({
  set(value) {
    return modifiers.uppercase  ? value.toUpperCase()  : value;
  }
});
</script>

结论: 可以看到在 vue 3.4 以后,代码量大幅减少,所以能升级就升级吧!

相关文章:

  • 大语言模型从理论到实践(第二版)-学习笔记(绪论)
  • 正则表达式简述
  • BP神经网络终极进化:2025量子增强版Python实现(附元宇宙金融实战)
  • 2025年03月07日Github流行趋势
  • STM32 子设备通过CAN发送数据到主设备
  • git 添加额外的远程仓库 URL
  • 【每日学点HarmonyOS Next知识】Web跨域资源、Web长按菜单、Web拦截请求、禁止录屏、Base64图片宽高
  • WHAT - 前端阻塞场景梳理
  • Hive-优化(语法优化篇)
  • 【Unity】 HTFramework框架(六十一)Project窗口文件夹锁定器
  • Vue 系列之:Vuex 和 Pinia
  • 直播流程管理 AI 应用的开发思路和功能实现
  • 从零开始玩转 Docker:用 Node.js 打印“Hello World”
  • IOC 篇
  • 机器学习数学基础:38.统计学模型变量
  • Android中的AsyncTask。
  • Redis--Hash类型
  • SQL 注入 (C++向)
  • 【Linux】初识make
  • 78.StringBuilder简单示例 C#例子 WPF例子
  • .net 导航网站模板/品牌推广软文案例
  • 网站内容上传/网站推广和优化的原因
  • 乐平市网站建设/免费b站在线观看人数在哪儿
  • 建设视频网站链接百度云盘/优秀网站设计赏析
  • 农村网站建设必要性/播放量自助下单平台
  • 电子商务及网站建设/企业网站源码