vue开发中的常见败招

vue开发中的常见败招

1 父子组件都是表单,父组件如何获取子组件中的值

js 复制代码
<parent-form>
  <child-form :initFormData="xxx"  ref="childForm">
  </child-form>
  <button @click="save">提交</button>
</parent-form>

假设有这样一个组件,父组件有自己的表单项,同时嵌套一个子组件也是表单,当父组件点击提交时候 需要获取子组件的数据,很多人都会直接用ref 直接获取子组件中的data属性,其实这是非常差劲的写法,

使用 ref 直接获取子组件的 data 虽然可行,但在 Vue 的开发模式中并不是最优解。

最优方案建议:使用 v-model 双向绑定

为什么 v-model 更好?

  1. 数据流清晰 :符合 Vue "Props down, Events up" 的核心原则。父组件不需要知道子组件内部变量叫什么(比如是叫 tableFormData 还是 ruleFormParams ),只需要关心绑定的数据。
  2. 解耦 :父组件不需要通过 ref 去探测子组件的内部状态。如果以后子组件内部重构了变量名,只要 v-model 协议不变,父组件代码无需任何改动。
  3. 实时同步 :父组件的 form 中始终保持着最新的表格数据,点击"保存"时直接提交 this.form 即可,不需要在提交瞬间去额外"收集"一次数据。

实现步骤

我已经为你完成了相关的代码重构,具体逻辑如下:

  1. 修改子组件支持 v-model 在 BodyTableForm.vue 和 ParamsTableForm.vue 中:
  • 将接收数据的 prop 从 params 改为 value (Vue 2 v-model 的默认 prop)。
  • 添加 watch 监听:
    • 监听 value :当父组件传入新数据时,同步给内部的 tableFormData 。
    • 监听 tableFormData :当表格内容发生变化(新增、删除、修改)时,通过 $emit('input', newVal) 通知父组件。
js 复制代码
// 子组件核心逻辑
props: {
  value: { type: Array, default: () => [] }
},
watch: {
  value: {
    handler(val) { this.tableFormData = val; },
    immediate: true, deep: true
  },
  tableFormData: {
    handler(val) { this.$emit('input', val); },
    deep: true
  }
}
  1. 父组件使用 v-model 绑定 在 ApiRequest/index.vue 中:
  • 移除了冗余的 computed 属性,改为在 data.form 中直接维护 params 和 requestBodyFields 。
  • 模板中直接使用 v-model 绑定。
js 复制代码
<!-- 父组件模板 -->
<BodyTableForm v-model="form.requestBodyFields" />
<ParamsTableForm v-model="form.params" />
  1. 完善初始化逻辑 在父组件的 initForm 中增加了 深拷贝 逻辑。这样可以确保子组件对数据的修改不会意外污染到 Vuex 原始数据,只有在点击"确定"提交后才会生效。

总结:其他可选方案对比

通过现在的 v-model 实现,你的父组件在点击"确定"时, this.form 已经包含了所有子表格的最新数据,逻辑非常自然。

2 "默认值覆盖"问题。

核心问题分析

当你使用 this.form = { ...this.form, ...this.apiInfo } 时,JavaScript 的对象展开运算符(Spread Operator)会遵循"后者覆盖前者"的原则。即便 this.apiInfo 中的字段值是 null 、 undefined 或 '' (空字符串),它依然会无情地覆盖掉 this.form 中预设的系统默认值(如 GET 或 FALSE )。

最优解:在组件初始化时使用"非空合并"策略

虽然可以在 Store 中处理,但我更建议在 组件的 initForm 方法中 解决。

原因 :

  1. UI 表现与数据分离 :Store 应该尽可能真实地反映后端返回的数据(哪怕是空的)。而"默认值"往往是 UI 层的表现需求。

  2. 灵活性 :不同的表单可能对同一个数据对象有不同的默认值需求。

  3. 可维护性 :在组件 data() 中定义的默认值一眼可见,维护起来最直观。 修改后的代码实现 我已经更新了 ApiRequest/index.vue 的逻辑:

    initForm () { if (this.apiInfo) { // 1. 先进行深拷贝,断开引用 const apiData = JSON.parse(JSON.stringify(this.apiInfo))

    kotlin 复制代码
     // 2. 关键逻辑:过滤掉 apiInfo 中的"空值"
     // 只有当 apiInfo 中的字段真正有内容时,才去覆盖 form 的默认值
     Object.keys(apiData).forEach(key => {
       const val = apiData[key]
       if (val === null || val === undefined || val === '') {
         delete apiData[key] // 如果是空值,从待合并对象中删除
       }
     })
    
     // 3. 执行合并
     this.form = {
       ...this.form,
       ...apiData
     }

    } },

为什么不建议在 Store 中处理?

  • Store 污染 :如果在 setOperationCurrentResource 突变中强行填入默认值,那么当你后续需要判断"这个字段是用户填的还是系统默认的"时,就会变得非常困难,因为原始的空状态已经丢失了。
  • 不可预测性 :全局 Store 的改动会影响所有引用该数据的组件。如果你在 Store 里把 null 变成了 GET ,某些只需要展示"暂无数据"的只读页面可能就会错误地显示出 GET 。

总结

通过在组件内采用 "非空合并" 策略:

  • 保留了默认值 :如果后端没传,保留 data() 里的 GET 。
  • 尊重了有效值 :如果后端传了 POST ,它会正确覆盖 GET 。
  • 保护了 Store :Vuex 里的数据依然是纯净的。 这种方案既解决了你的覆盖问题,又保证了代码的健壮性和可维护性。
相关推荐
IT_陈寒6 分钟前
React重渲染这坑,我跳进去又爬出来了
前端·人工智能·后端
郑州光合科技余经理2 小时前
本地生活系统:多业务订单字段怎么分账本导出
java·开发语言·前端·数据库·uni-app·php·ai编程
怕浪猫8 小时前
FDE 如何正确解决现场项目工程性的问题
前端·后端·ai编程
西瓜太郎12349 小时前
外层模型卡片与分组详情成功率不一致,应该怎么排查?
前端·typescript·go·软件工程·react
GreenTea9 小时前
vLLM 与 SGLang KV Cache 底层实现机制深度调研报告
前端·后端·算法
几何心凉12 小时前
没有万能模型:我用 AiiOnly Token Plan,把多款大模型的长处拼进同一个项目
前端
kyriewen12 小时前
Claude Code 的额度今天缩水了17%——官方公告上写的是"永久提高25%"
前端·ai编程·claude
雪芽蓝域zzs13 小时前
vue解构平铺VS对象包裹
前端·javascript·vue.js
风骏时光牛马13 小时前
从零到实战,完整AI学习路线
前端
三十而立洋14 小时前
深入理解 Monorepo:子包安装依赖
前端·前端工程化