element-ui小技巧:优雅的处理表单联动

在Vue中,处理表单联动是业务代码中常见的需求。本文介绍了一个优雅的方法,通过自定义指令实现了在表单控件从页面上消失时,与其关联的字段值自动重置的功能。通过观察Element-UI的DOM结构,以及使用MutationObserver API,我们能够更智能地管理表单的状态。这样的实践使得代码更加清晰、模块化,并减少了大量重复的代码,提高了代码的可维护性。这种方法不仅适用于简单的联动需求,也可以处理复杂的表单联动逻辑,为开发者提供了更高效的开发体验。通过这个技巧,我们能够更加灵活地应对不同业务场景下的表单联动需求,提升了前端开发的效率和质量。

问题

在业务代码编写过程中,我们常常需要满足表单控件之间的联动展示需求。这样的联动经常涉及到根据选择的条件来展示相应的输入控件。在大多数情况下,提交到后端的数据就是页面上显示的输入控件中的数据。因此,在条件切换时,当前值关联的输入控件的内容应该被清空。

通常,我们会写出如下的代码

vue 复制代码
<template>
  <div>
    <el-form :model="formData" label-width="80px">
      <el-form-item label="条件选择" prop="condition">
        <el-select v-model="formData.condition" @change="handleConditionChange">
          <el-option label="条件A" value="A"></el-option>
          <el-option label="条件B" value="B"></el-option>
        </el-select>
      </el-form-item>
      <!-- 根据条件展示不同的组件 -->
      <el-form-item  v-if="formData.condition === 'A'" label="组件A" prop="inputValueA">
        <el-input  v-model="formData.inputValueA" />
      </el-form-item>
      <el-form-item v-else label="组件B" prop="inputValueB">
       <el-input  v-model="formData.inputValueB" />
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
  data() {
    return {
      formData: {
        conditionA: '',
        inputValueA: '',
        inputValueB: '',
      },
    };
  },
  methods: {
    handleConditionChange() {
      this.formData.inputValueA = "";
      this.formData.inputValueB = "";
    },
  },
};
</script>

上述代码在简单情况下是可行的,但当联动层级较多或表单联动穿插了更复杂的逻辑时,需要编写越来越多的 handleChange 方法。有没有一种方法,在控件从页面上消失时,它绑定的值也能够自动重置呢?

为了实现这个目标,我们可以采用如下的思路:

  1. 将输入控件关联的字段信息存储在对应的 DOM 上。
  2. 监听输入控件的 DOM 节点删除,从删除的节点中找到对应字段并进行重置。

对于第一点,通过观察 Element-UI 的 DOM 结构,我们发现 el-form-itemprop 会绑定到 DOM 结构的 labelfor 属性上。

有了这个准备,接下来就是监听DOM节点的删除,直接MutationObserver就完事了

MutationObserver是一个JavaScript的API,用于监测DOM树的变化。它提供了一种异步的方式来监听DOM元素的增加、删除、属性变化等操作,以及文本节点的修改。通过MutationObserver,开发者可以实时地捕捉到DOM的变化,并做出相应的响应。

完事具备,接下来就是要设计一个简单易用的使用方式了,封装为指令最为合适不过

ini 复制代码
<el-form  :model="formData" v-reset-fields>

</el-form>

指令的实现如下

javascript 复制代码
Vue.directive('reset-fields', {
  inserted(el, binding, vnode) {
    const targetNode = el
    const componentInstance = vnode.componentInstance
    if (!componentInstance.model) {
      throw new Error('reset-fields指令只能用于配置了model选项的el-form组件')
    }
    const config = { childList: true }
    // 当观察到变动时执行的回调函数
    const callback = (mutationsList) => {
      if (mutationsList) {
        for (const mutation of mutationsList) {
          if (mutation.type === 'childList') {
            if (mutation.removedNodes.length > 0) {
              // 查出所有被移除的form-item包裹的表单字段名
              const bindingValue = []
              mutation.removedNodes.forEach((item) => {
                let formItemEls = null
                if (item.classList && item.classList.contains('el-form-item')) {
                  formItemEls = [item]
                } else if (item.querySelectorAll) {
                  formItemEls = item.querySelectorAll('.el-form-item')
                }
                if (formItemEls) {
                  formItemEls.forEach((formItemEl) => {
                    const field = formItemEl.querySelector('label').getAttribute('for')
                    bindingValue.push(field)
                  })
                }
              })
              // 重置字段
              if (bindingValue.length > 0) {
                const model = componentInstance.model
                bindingValue.forEach((field) => {
                  if (Array.isArray(model[field])) {
                    model[field] = []
                  } else {
                    model[field] = undefined
                  }
                })
              }
            }
          }
        }
      }
    }
    // 创建一个观察器实例并传入回调函数
    const observer = new MutationObserver(callback)
    // 以上述配置开始观察目标节点
    observer.observe(targetNode, config)
    // 保存观察器实例,用于解绑
    el.mutationOb = observer
  },
  unbind(el) {
    el.mutationOb.disconnect()
  },
})
相关推荐
一 乐1 小时前
租拼车平台|小区租拼车管理|基于java的小区租拼车管理信息系统小程序设计与实现(源码+数据库+文档)
java·数据库·vue.js·微信·notepad++·拼车
寻找09之夏5 小时前
【Vue3实战】:用导航守卫拦截未保存的编辑,提升用户体验
前端·vue.js
多多米10056 小时前
初学Vue(2)
前端·javascript·vue.js
看到请催我学习6 小时前
内存缓存和硬盘缓存
开发语言·前端·javascript·vue.js·缓存·ecmascript
golitter.8 小时前
Vue组件库Element-ui
前端·vue.js·ui
道爷我悟了8 小时前
Vue入门-指令学习-v-on
javascript·vue.js·学习
.生产的驴9 小时前
Electron Vue框架环境搭建 Vue3环境搭建
java·前端·vue.js·spring boot·后端·electron·ecmascript
老齐谈电商9 小时前
Electron桌面应用打包现有的vue项目
javascript·vue.js·electron
LIURUOYU42130810 小时前
vue.js组建开发
vue.js
九圣残炎10 小时前
【Vue】vue-admin-template项目搭建
前端·vue.js·arcgis