需求的开始

一个表单,里面有很多表单项,然后需求通过特定的条件会触发某些表单项的显隐,条件会有很多很多,但是会有个问题,就例如:

  • a输入框:显示状态,输入了值5,对应的属性值为5
  • 通过了某个条件触发了让a输入框隐藏
  • a输入框:隐藏状态,对应的属性值为5
  • 这个时候提交表单,后端就接收到a输入框的值,但是实际a输入框这个时候是隐藏状态,就是并不想接受到a输入框的值

所以,在a输入框隐藏状态,提交给后端的数据a输入框对应的值应该是空的才对,这么一看那我们的需求是不是就是:

  • a输入框隐藏时候就(v-if初始化组件)恢复对应的初始属性

但其实这样做并不好,让我们想想,就是例如一个开关,点一下控制10个表单项的显隐,用户好不容易填写了10个表单项,然后不小心点了一下开关把表单项给隐藏了,于是又重新点击开关把10个表单项给打开,但是却发现辛辛苦苦填写的10个表单项没有了,这谁受得了,所以我们的需求其实是这样的:

  • a输入框隐藏时候不要恢复初始值,重新显示还要可以看到刚刚填的值
  • 表单隐藏的时候再去不要把输入框修改值提交,要提交隐藏输入框的初始值

初步思路:标记方案

对应的我们的思路应该是这样:

  • 我们需要一个标记,就是当我们隐藏输入框时候,对应标记我这个属性现在是隐藏值,如果显示时候,再把对应的隐藏标记去掉
  • 然后提交的时候,我们需要根据标记把是隐藏值的属性给恢复初始值去提交

有别的超简单的方案?

会有人觉得这个思路挺麻烦,那我只要提交的时候根据开关判断一下然后改变一下值不就好了吗,就例如:

let open = false; // 开关
let form = { // 表单的值
  name: '',
  age: '',
};
if (open === true) {
  submit(form); // 如果开关是开的,那就正常提交目前的表单,是改了什么值就什么值
} else {
  form.name = ''; // 如果开关是关的,那我手写这个代码把变量恢复空就好了
  form.age = '';
  submit(form);
}

突然是不是觉得上面那段代码已经可以解决问题了,之前的都是废话?其实并不是,开头就标明了,表单项有很多,200个?300个?,你觉得你也可以手写,那ok,如果加上20种不同的条件判断呢?

这个时候你要写多少代码,而且这样复杂度很高,代码也很难阅读,所以我才会想用标记记录。ok,否了这个“简单”的方案后,我们继续讨论之前的思路。

继续标记方案

分析如何实现

  • 让我们设置一个标记数组用来保存隐藏的,例如

const hideTag = []

  • 然后只要对应的表单项目隐藏,我们就给标记数组添加上标记,name就是form表单里面的表单项的属性

{ prop: 'name' } => const = tag = [{ prop: 'name' } ];

  • 如果对应的表单项显示,那么我们就从标记数组把对应的属性给移除
  • 提交的时候,我们就从标记数组找对应的属性,我们就把form表单对应的值给清空

然后我们来分析一下怎么实现:

  • 第一点很容易实现,自己新建一个变量就行了
  • 第二点第三点都是一个意思就是在表单项显示隐藏的时候触发一个事件,可以拿到属性名和显隐状态,

这个时候我们可以通过本身的显隐逻辑代码的时候,去增加代码,去通知到也页面这个属性要显示还是隐藏,但是实际上也是会混入非常多的代码在显隐逻辑的代码片段,所以不是很好

那样我们能不能这样,给我们的组件一个方法,当组件销毁和创建的时候发出一个事件,然后我们页面捕获这个事件再去逻辑,这个就很好,就不需要添加很多代码,

只需要在表单项组件的生命周期添加两个方法即可,因为你的属性这些内容,表单组件都是需要的所以都我们需要的属性名和显隐状态都有了

然后还需要引入一个 bus事件总线 ,来作为发射事件的导体,因为我的页面组件比较多,曾经比较复杂,如果页面层级相对简单的也可以使用自组件自带的 emit事件

具体如何实现在表单项组件添加显隐逻辑事件

  • 我们用到的组件是element-ui的el-form-item组件,我们需要往里面添加两个事件分别在创建和销毁的时候触发,因为用了v-if指令来做显隐的效果,所以只要隐藏就会触发销毁的生命周期destroyed,显示就会触发创建完成dom元素的的生命周期mounted
  • 但是我们怎么添加方法,你都说了是element-ui的组件,难道你要我改源码?而且改源码并不能直接去改你的安装的element-uinpm包,一般我们要是想改到源码里面的代码就需要根据源代码,做了修改然后自己发布一个npm的包,然后重新引用来使用,这样的流程就太麻烦了,其他同事都得重新安装新的包
  • 还有个跟简单的方法,我们直接找到element-uiel-form-item组件,我们直接新建一个组件oa-form-item然后复制el-form-item这个组件的代码出来

(在项目里面element-ui的el-form-item组件)

复制的时候需要注意,el-form-item里面还引入了一个组件label-warp,这个也要复制过来,或者你把引导的代码修改一下:

之前:

import LabelWrap from './label-wrap';

修改:

import LabelWrap from ‘element-ui/packages/form/src/label-warp’

不然引用会报错,复制组件过来或者你修改引用路径都行,反正要保证原来代码的引用都是正常的

(label-warp组件)

  • 复制完成之后我们就要往他里面添加bus事件总线,以及两段代码,这样我们就可以和el-form-item一样使用该组件了,代码如下:
// 引入eventBus
import {bus} from '@/bus';
// mounted添加显示事件
mounted() {
    // 两个个参数:
    // 第一个字段属性:name,或者多层的结构 person.age, human.yellow.name
    // 第二个是显隐状态:true就是显式,false就是隐藏
    bus.$emit('destroy-val', this.prop, true);
}
// destory添加隐藏事件
destroyed() {
   // 参数和显示是一样含义
    bus.$emit('destroy-val', this.prop, false)
  },
import Vue form 'vue;
export var bus = new Vue();
  • 接着我们就要在主页面接受事件的触发然后添加移除hideTag数组的元素:
import {bus} from '@/bus';
export default {
  data() {
    return {
      hideTag: [],
    }
  },
  method: {
    // 根据显隐改变hideTag数组
    changeHideTag() {
                           // prop 就是属性名:name, human.yellow.name 
                           // isCreate 就是显隐:true就是显示,false就是隐藏
    bus.$on("destroy-val", (prop, isCreate) => {
      if (isCreate) {
        // 这个是显示的情况,所以我们要过滤一下,把对应隐藏的属性名去掉
        // prop: 'name', hideTag: ['name'] => hideTag: []
        this.hideTag = this.hideTag.filter(propName => propName !== prop );
      } else {
        // 这个是隐藏的情况,我们需要添加进入标记数组
        // prop: 'name', hideTag: [] => hideTag: ['name']
        props.forEach(prop => {this.hideTag.push(prop)});
      }
    });
  },
  }
}
  • 完成的标记数组的存储之后,就是最后一步,提交的时候根据标记数组的属性名,把对应的属性清空:
import {bus} from '@/bus';
export default {
  data() {
    return {
      hideTag: [],
      // 表单对象
      form: {
        name: '',
        human: {
          yellow: {
            name: ''
          }
        }
      }
    }
  },
  method: {
// 根据hideTag清除对应的属性
    clearHiddenBlockVal() {
// 这是根据映射去清除fields对应值
        this.hideTag.forEach(item => {
// name => [name], human.yellow.name => [human, yellow, name]
            let propsStr = item.split(".");
// 这里的reduce最后不返回东西,目的是去到对象最后一层清空
            propsStr.reduce((pre, next, index, arr) => {
// 这里判断,如果是循环到属性的最后一层,也就是例如 obj.name => [obj, name] => 到name就是最后了,那就吧对应值清空
                if (index === arr.length - 1) {
                    pre[next] = '';
                } else {
                    return pre[next];
                }
            }, this.form);
            });
        },
  }
}
// 如果不知道reduce是怎么用法,地址在这里
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

结尾

以上就是整个的解决思路和实现,具体实施的过程要根据自己的场景作出一些改变,

  • 比如有些表单项他是绑定两个属性名称的,那么我们可以在在复制出来的oa-form-item自定义多一个属性,props传进去数组属性,相应的函数也要做些许改变。
  • 还有这里我们表单其实初始值基本都是空值,如果是有初始值的可以搞个初始值对象来对比

以上就是element-ui表单提交自动清空隐藏表单值实现的详细内容,更多关于element-ui表单提交值清空的资料请关注阿兔在线工具其它相关文章!

点赞(0)

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部