Vue3中父子表单组件数据同步问题

Posted 前端发现

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue3中父子表单组件数据同步问题相关的知识,希望对你有一定的参考价值。

前言:

有段时间没有更新文章了,最近工作中遇到某个Vue表单文件复杂度代码行数高达5K+,为此页面更新时有些许卡顿,当时决定将这个Vue表单文件抽离成几个小表单的结构,便于今后的项目维护和功能迭代。

所以今天给大家带来的是Vue3中对于大型表单组件如何抽离小表单组件以及父子组件数据同步问题。

以下提供三种方案,由上到下逐步优化。

先来看页面的效果(以下案例均按照如下页面效果实现):

方案一:

  • 子组件自行维护各自表单数据,更新后同步到父组件。
  • 父组件表单数据变更时,设置子组件的表单回显。

父组件如何实现?:

由此可见父组件定义了ruleForm对象,用于整合整个大型表单文件的数据存储。 changeSonForm方法用于接受子组件表单数据变更时传递的最新数据,然后做覆盖ruleForm对象的操作。实现子组件表单数据同步到父组件中。

再看子组件的实现?:

子组件自行维护sonForm对象,并且利用watch深度监听该对象,对象属性变更时同步给父组件,更新父组件的ruleForm对象,这样就父子组件表单的值就能够同步。

那要是页面挂载完成时需要初始化表单值怎么做呢?未抽离时直接覆盖ruleForm对象就好了,但是现在部分表单的数据已经抽离到子组件了,那么就需要去初始化子组件的表单了。

/** 子组件 */
/** 提供一个方法,供父组件刷新子组件的值 */
const initSonForm = (form: FormType) => 
  Object.assign(sonForm, form);
;
/** 子组件暴露出去的变量|方法 */
defineExpose(
  initSonForm,
);
/** 父组件 */
const sonRef = ref();
onMounted(() => 
  /**模拟更改ruleForm的数据,初始化子组件的表单数据 */
  ruleForm.name = "我是父组件修改的值";
  ruleForm.open = true;
  /** 触发子组件提供的方法 */
  sonRef.value?.initSonForm(
    name: ruleForm.name,
    type: ruleForm.type,
    open: ruleForm.open,
    citys: ruleForm.citys,
  );
);

缺点:

  • 父组件需要维护一套子组件的表单对象。
  • 数据流动混乱,子父组件各自调动初始化数据,打破数据单向流动性规则。
  • 项目维护难度大。

方案二:

  • 父组件维护数据,传递整个表单对象。

父组件实现?:

所有的数据均由父组件维护,表单对象通过属性传递给子组件,子组件通过props接收并直接绑定到自己的表单中。

此时数据时互通的,不需要子组件表单项更新时同步到父组件,父组件的表单变更也会响应式更新到子组件。

看起来方案二已经完美无瑕了,但是忽略了一点:子组件收到父组件的表单对象是直接绑定到v-model中的,相当于直接更改了父组件传递过来的值,这是官方不建议的,且引入了eslint也会报出警告⚠️。

缺点:

  • 子组件直接更改了父组件的值,打破数据单向流动性规则。

方案三:

  • 父组件维护数据,通过v-model传递表单对象。
  • 子组件收到的对象不直接绑定到表单,利用computed做一层中转。

直接看父组件:

值得注意的是这里的ruleForm对象改为了ref声明,且在子组件传递处改为了v-model=“ruleForm”

原因:使用reactive覆盖表单对象会使ruleForm失去响应式。

子组件实现:

表单变更时控制台输出:

考虑到此表单组件抽离是常见的场景,特写成通用的hooks函数。代码如下:

你可能会疑惑:
什么时候会触发外层的set函数?

  • 答:只有当props[propName]整个对象被重新赋值时会触发。

以上就是此次分享的全部内容啦。

结语:

表单组件抽离在开发中很常见,切不可打破数据单向流动性数规则,否则,打破地越多,代码离屎山就越近!

Vue父子组件间通信(数据传递)

参考技术A

父---props--->子
子---props/自定义事件/全局事件总线/消息订阅与发布--->父
任意组件间通信:/自定义事件/全局事件总线/消息订阅与发布/Vuex/路由传参

父组件传递:在使用子组件时,使用 v-bind:自定义接收名称="要传递的数据"
子组件接收: props:["自定义接收名称"]

父组件传递: v-on:自定义接收名称="要传递的方法"
子组件接收时自定义一个方法,在方法中触发父组件传递的方法: this.$emit("自定义接收名称")

在父组件向子组件 传递方法 的基础上,给方法 增加参数
也就是在子组件中触发父组件的方法时: this.$emit("自定义接收名称",需传递的数据) ,父组件中的方法也增加参数接收数据即可。

在父组件中使用子组件时,增加 ref属性并指定ref的名称 ,然后在调用方法的地方使用 this.refs.ref的名称.需调用的子组件方法名() 即可调用。
e.g.

以上是关于Vue3中父子表单组件数据同步问题的主要内容,如果未能解决你的问题,请参考以下文章

通俗易懂:Vue.js 组件之间传递数据

第四节:Vue表单标签和组件的基本用法,父子组件间的通信

Vue初步了解组件——父子组件

vue.js 组件之间传递数据

Vue.js 父子组件,为啥我的 prop 在子组件中还没有?

「 VUE3 + TS + Vite 」父子组件间如何通信?