element-ui表單提交自動清空隱藏表單值實現

需求的開始

一個表單,裡面有很多表單項,然後需求通過特定的條件會觸發某些表單項的顯隱,條件會有很多很多,但是會有個問題,就例如:

  • 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表單提交值清空的資料請關註WalkonNet其它相關文章!

推薦閱讀: