Element Plus表单调用resetFields方法失效解决方案,论nextTick函数的重要性!

文章讲述了在Vue3项目中使用ElementUI时,表单复用遇到的问题,即表单数据在关闭对话框后未清空。原因是el-dialog组件的懒加载导致表单初始化延迟。通过使用Vue的nextTick函数,解决了在打开和关闭对话框时数据拷贝的时机问题,确保表单清空的正确性。
摘要由CSDN通过智能技术生成

image.png

场景复现

在我们日常 Vue3 开发当中,总是会离不开 Element UI 组件库,组件库中还是得属表单和表格的使用频率最高。比如,后台管理系统中,会大量地使用表格和表单。而且,我们通常都会在开发 CRUD 接口的时候复用同一个表单和对话框来实现查看详情、新增数据、修改数据的效果,这样可以大大减少冗余视图结构代码,提高代码复用性。

具体一点讲,在点击新增按钮的时候,会弹出对话框显示添加数据的表单。在编辑数据的时候会弹出对话框提示你修改数据。当对话框关闭的时候,我们还需要清空表单,防止在点击新增按钮的时候之前编辑的数据还出现表单中这种低级错误。

但是有时候,你会发现在第一次点击新增按钮的时候然后再点击编辑按钮再点击新增按钮表单是可以正常清空的。但是如果你第一次点击编辑按钮,表单数据回显,关闭窗口再点击新增按钮发现编辑的数据竟然还在,就很玄乎。而且,你点击编辑其他数据再点击新增按钮发现竟然是第一次点击编辑的数据

这究竟是为什么呢?真是太抽象了。就如下图所示:

在一个 Tab 组件内部嵌套了一个用户列表组件,因为列表组件可能代码逻辑会特别多,所以封装了组件。

image.png

App.vue:

```js HelloWorld

```

UserTable:

```js 新增 删除 详情 编辑

```

第一次点击编辑或详情:

image.png

然后点击新增按钮:

image.png

你会发现第一次编辑的数据还在!你会疑问为啥还在呢?我不是在窗口关闭的时候绑定了回调函数吗,还传入了表单的引用,调用了 resetFields 方法清空表单:

js function handleClosed(formRef) { formRef.resetFields() }

原因分析

经过大量查阅资料了解到,el-dialog 组件是懒加载的,在这种 Tab 页内部嵌套组件的做法会导致 el-form 和 el-dialog 加载时机不一致。在 el-dialog 显示出来以后才会加载内部的组件,在加载完成之前,调用 Object.assign(form, row) 方法给表单绑定值拷贝属性赋值操作会先完成,最后在加载完成之后,表单对象就会得到一个错误的初始值,相当于把用户定义的初始值给覆盖了。简单来讲就是用户定义的初始值还没来得及绑定呢就被覆盖了。

具体来讲就是 hanldeEdit 方法在 const form = ref({...}) 之前发生,所以用户定义的初始值就没用了。在后面的清空表单操作中,都是以第一次编辑的数据为初始值来清空。

所以得让拷贝数据赋值操作延后执行。

解决方法

在 Vue3 中,nextTick 函数可以让一些操作延后执行,当你修改了响应式状态时,DOM 会被自动更新。但是需要注意的是,DOM 更新不是同步的。Vue 会在“next tick”更新周期中缓冲所有状态的修改,以确保不管你进行了多少次状态修改,每个组件都只会被更新一次。

要等待 DOM 更新完成后再执行额外的代码,可以使用 nextTick() 全局 API:

js function nextTick(callback?: () => void): Promise<void>

当你在 Vue 中更改响应式状态时,最终的 DOM 更新并不是同步生效的,而是由 Vue 将它们缓存在一个队列中,直到下一个“tick”才一起执行。这样是为了确保每个组件无论发生多少状态改变,都仅执行一次更新。

nextTick() 可以在状态改变后立即使用,以等待 DOM 更新完成。你可以传递一个回调函数作为参数,或者 await 返回的 Promise。

```js

```

所以可以使用 nextTick 函数优化拷贝赋值操作:

```js function handleView(row) { dialogProps.value.visible = true dialogProps.value.title = '查看用户数据' nextTick(() => { Object.assign(dialogForm.value, row) }) }

function handleEdit(row) { dialogProps.value.visible = true dialogProps.value.title = '修改用户数据' nextTick(() => { Object.assign(dialogForm.value, row) }) } ```

最终效果如下,第一次先点击编辑:

image.png

再点击新增:

image.png

成功清空表单数据。

思考

为什么这里 DOM 的修改没有同步更新呢,因为这边嵌套了一个 UserTable 组件,子组件的状态修改不一定会及时更新,所以得要等待下一个"钩子"来临的时候一起更新。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值