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 里的数据依然是纯净的。 这种方案既解决了你的覆盖问题,又保证了代码的健壮性和可维护性。
相关推荐
清秋23 分钟前
全网最全 ECMAScript 攻略( 更新至 ES2026)
前端·javascript·编程语言
Cao_Ron40 分钟前
用 SVG image symbol 画 ECharts graph 圆形节点
前端
hxy06011 小时前
React-Call让你的React组件像异步函数一样调用
前端·react.js
Hilaku1 小时前
为什么 AI 写前端时,总是优先选择 React,而不是 Vue?
前端·javascript·程序员
京东云开发者1 小时前
GPT-5.6、ChatGPT Work 与 Codex 更新食用指南
前端
Cao_Ron1 小时前
用 ECharts graph 画出卡片式矩形节点
前端
skiyee1 小时前
换个底座的 Wot Starter 居然让 AI 更懂项目!
前端·ai编程
anyup1 小时前
这一套绝了!AI 大模型写故事,星云 SDK 驱动 3D 数字人实时演绎
前端·人工智能·aigc
耀耀切克闹灬2 小时前
短链跳转
前端
孟陬2 小时前
高质量全方位的 AI 工具 sse-stuntman — Mock SSE 接口
前端·node.js·openai