Vue3組件(十)封裝一個成熟的表單(下)

一個成熟的表單

表單表單,你已經(jīng)長大了力惯,你要學(xué)會:

  • 動態(tài)渲染
  • 支持單列碗誉、雙列、多列
  • 支持調(diào)整布局
  • 支持表單驗證
  • 支持調(diào)整排列(顯示)順序
  • 依據(jù)組件值顯示需要的組件
  • 支持 item 擴展組件
  • 可以自動創(chuàng)建 model

這個表單控件是基于 element-plus 的 el-form 做的二次封裝父晶,所以首先感謝 element-plus 提供了這么強大的UI庫哮缺,以前用jQuery做過類似的,但是非常麻煩甲喝,既不好看尝苇,可維護性、擴展性也差埠胖,好多想法都實現(xiàn)不了(技術(shù)有限)糠溜。
現(xiàn)在好了,站在巨人的肩膀上直撤,以前的想法都可以實現(xiàn)了非竿。

大圖預(yù)警:這里有好幾張大 gif 圖片,流量不夠的話慎開谋竖。汽馋。。

調(diào)整排列(顯示)順序以及調(diào)整布局

既然是動態(tài)渲染圈盔,那么組件的顯示順序也應(yīng)該可以靈活調(diào)整豹芯。
所以設(shè)計了一個顯示用的數(shù)組,把組件ID存放進去驱敲,v-for的時候铁蹈,遍歷這個數(shù)組就可以實現(xiàn)調(diào)整顯示順序的需求了。

單列的調(diào)整順序众眨,以及調(diào)整布局

動態(tài)表單003單列調(diào)整01.gif

導(dǎo)出MP4才400多k握牧,導(dǎo)出gif居然2M多容诬。真的好無語。
可以插入沿腰,可以交換览徒,可以把幾個短的擠到一行。

多列的調(diào)整順序颂龙,以及調(diào)整布局

動態(tài)表單004雙列調(diào)整2.gif

掐了一半沒播习蓬,因為gif太大了。
還是插入措嵌、交換躲叼,可以讓一個組件獨占一行。

多列也是一樣的操作企巢。

依據(jù)組件值顯示需要的組件

有的時候表單里的組件并不是都需要用戶填寫的枫慷,比如注冊域名的時候,公司注冊需要填寫公司名稱等信息浪规,而個人注冊顯然沒有公司信息可以填或听,那么這時候表單就需要根據(jù)用戶的選擇(公司、個人)來顯示不同的字段來讓用戶填寫笋婿。

這時候就需要一個運行時調(diào)整的功能誉裆。
其實現(xiàn)原理,還是通過調(diào)整那個排序用的數(shù)組來實現(xiàn)的萌抵。
先看一下效果:


動態(tài)表單005依據(jù)值顯示其他組件.gif

還是這么大。元镀。绍填。
下拉列表里面選擇不同的選項,會顯示對應(yīng)的組件栖疑。這種對應(yīng)并不是寫死的表單控件里面讨永,而是可以在外部配置出來。

監(jiān)聽組件的值遇革,然后修改排序用的數(shù)組

  • json文件:
    "formColShow": {
      "103": {
        "101" : [101, 102, 103, 104],
        "102" : [101, 102, 103, 106, 107, 104, 105],
        "103" : [101, 102, 103, 104, 105]
      } 
    },

依據(jù)組件的編號卿闹,指定每個組件值對應(yīng)需要顯示的組件ID。
似乎有點太抽象了萝快,其實就是應(yīng)為抽象出來共同的特點锻霎,才可以實現(xiàn)這樣的功能呀。

  // 設(shè)置組件的顯示順序
  const setFormColSort = (array = formMeta.colOrder) => {
    formColSort.length = 0
    formColSort.push(...array)
  }
  // 監(jiān)聽組件值的變化揪漩,調(diào)整組件的顯示以及顯示順序
  if (typeof formMeta.formColShow !== 'undefined') {
    for (const key in formMeta.formColShow) {
      const ctl = formMeta.formColShow[key]
      const colName = formItemMeta[key].colName
      watch(() => formModel[colName], (v1, v2) => {
        if (typeof ctl[v1] === 'undefined') {
          // 沒有設(shè)定旋恼,顯示默認組件
          setFormColSort()
        } else {
          // 按照設(shè)定顯示組件
          setFormColSort(ctl[v1])
        }
      })
    }
  }

遍歷 formColShow ,監(jiān)聽里面的組件的值奄容,有變化了就按照值去加載對應(yīng)的組件ID冰更,如果沒有就加載默認組件产徊。

自動創(chuàng)建 model

我比較懶,不想寫model的定義代碼蜀细,太麻煩舟铜。
尤其當(dāng)需求變更的時候,又要改代碼奠衔。
那么能不能自動創(chuàng)建呢谆刨?于是寫了個函數(shù)。

完整的model

表單里面有多少組件涣觉,就創(chuàng)建多少個屬性痴荐。

  // 根據(jù)表單元素meta,創(chuàng)建 v-model
  const createModel = () => {
    // 依據(jù)meta官册,創(chuàng)建module
    for (const key in formItemMeta) {
      const m = formItemMeta[key]
      // 根據(jù)控件類型設(shè)置屬性值
      switch (m.controlType) {
        case 100: // 文本類
        case 101:
        case 102:
        case 103:
        case 104:
        case 105:
        case 106:
        case 107:
        case 130:
        case 131:
          formModel[m.colName] = ''
          break
        case 110: // 日期
        case 111: // 日期時間
        case 112: // 年月
        case 114: // 年
        case 113: // 年周
          formModel[m.colName] = null
          break
        case 115: // 任意時間
          formModel[m.colName] = '00:00:00'
          break
        case 116: // 選擇時間
          formModel[m.colName] = '00:00'
          break
        case 120: // 數(shù)字
        case 121:
          formModel[m.colName] = 0
          break
        case 150: // 勾選
        case 151: // 開關(guān)
          formModel[m.colName] = false
          break
        case 153: // 單選組
        case 160: // 下拉單選
        case 162: // 下拉聯(lián)動
          formModel[m.colName] = null
          break
        case 152: // 多選組
        case 161: // 下拉多選
          formModel[m.colName] = []
          break
      }
      // 看看有沒有設(shè)置默認值
      if (typeof m.defaultValue !== 'undefined') {
        switch (m.defaultValue) {
          case '':
            break
          case '{}':
            formModel[m.colName] = {}
            break
          case '[]':
            formModel[m.colName] = []
            break
          case 'date':
            formModel[m.colName] = new Date()
            break
          default:
            formModel[m.colName] = m.defaultValue
            break
        }
      }
    }
    // 同步父組件的v-model
    context.emit('update:modelValue', formModel)
    return formModel
  }

雖然有點長生兆,但都是簡單的case判斷。這樣就省去了手擼 model 的麻煩膝宁。

依據(jù)選項創(chuàng)建 model

因為支持依據(jù)用戶的選擇而現(xiàn)實不同的組件鸦难,那么創(chuàng)建的model是否也需要調(diào)整呢?所以又寫了個函數(shù)员淫。兩種 model 同時支持合蔽,這樣需要哪個就可以用哪個。

  // 依據(jù)用戶選項介返,創(chuàng)建對應(yīng)的 model
  const createPartModel = (array) => {
    // 先刪除屬性
    for (const key in formPartModel) {
      delete formPartModel[key]
    }
    // 建立新屬性
    for (let i = 0; i < array.length; i++) {
      const colName = formItemMeta[array[i]].colName
      formPartModel[colName] = formModel[colName]
    }
  }

先把原有的屬性刪掉拴事,然后再加上新的屬性。

支持 擴展組件

自帶的組件肯定是不夠的圣蝎,因為用戶的需求總是千變?nèi)f化的刃宵,那么新組件如何加入到表單控件里面呢?可以按照接口定義封裝成符合要求的組件徘公,然后做一個map字典牲证,就可以設(shè)置進去了。

因為接口統(tǒng)一关面,所以可以適應(yīng)表單控件的調(diào)用坦袍。

簡單的方法是,直接修改兩個js文件等太。
如果不方便修改的話捂齐,也可以通過屬性傳遞進來。目前暫時還沒有想好細節(jié)缩抡,不過似乎不是太難辛燥。

動態(tài)渲染

引入json,然后作為屬性傳入表單控件,然后就可以了挎塌。
這樣我們再實現(xiàn)添加徘六、修改的功能的時候,就不是寫代碼榴都,而是寫json了待锈,另外劇透一下,這個json當(dāng)然是不需要手擼的嘴高,我這么懶竿音。


005json數(shù)據(jù).png

單列、雙列拴驮、多列以及調(diào)整布局

這個其實就是個 v-for 的功能春瞬,使用el-cow、el-col 設(shè)置好span就可以實現(xiàn)套啤。

  // 根據(jù)配置里面的colCount宽气,設(shè)置 formColSpan
  const setFormColSpan = () => {
    const formColCount = formMeta.formColCount // 列數(shù)
    const moreColSpan = 24 / formColCount // 一個格子占多少份

    if (formColCount === 1) {
    // 一列的情況
      for (const key in formItemMeta) {
        const m = formItemMeta[key]
        if (typeof m.colCount === 'undefined') {
          formColSpan[m.controlId] = moreColSpan
        } else {
          if (m.colCount >= 1) {
            // 單列,多占的也只有24格
            formColSpan[m.controlId] = moreColSpan
          } else if (m.colCount < 0) {
            // 擠一擠的情況潜沦, 24 除以 占的份數(shù)
            formColSpan[m.controlId] = moreColSpan / (0 - m.colCount)
          }
        }
      }
    } else {
      // 多列的情況
      for (const key in formItemMeta) {
        const m = formItemMeta[key]
        if (typeof m.colCount === 'undefined') {
          formColSpan[m.controlId] = moreColSpan
        } else {
          if (m.colCount < 0 || m.colCount === 1) {
            // 多列萄涯,擠一擠的占一份
            formColSpan[m.controlId] = moreColSpan
          } else if (m.colCount > 1) {
            // 多列,占的格子數(shù) * 份數(shù)
            formColSpan[m.controlId] = moreColSpan * m.colCount
          }
        }
      }
    }
  }
  // 先運行一次
  setFormColSpan()

  // 設(shè)置組件的顯示順序
  const setFormColSort = (array = formMeta.colOrder) => {
    formColSort.length = 0
    formColSort.push(...array)
  }
  // 先運行一下
  setFormColSort()

表單驗證

這個使用el-form提供的驗證功能唆鸡。
目前暫時還沒有歸納好el-form的驗證涝影,因為需要把這個驗證用的數(shù)據(jù)寫入到j(luò)son里面,然后讀取出來設(shè)置好即可争占。
所以肯定沒難度燃逻,只是需要點時間。

源碼

https://github.com/naturefwvue/nf-vue-element

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末臂痕,一起剝皮案震驚了整個濱河市伯襟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌刻蟹,老刑警劉巖逗旁,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嘿辟,死亡現(xiàn)場離奇詭異舆瘪,居然都是意外死亡,警方通過查閱死者的電腦和手機红伦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門英古,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人昙读,你說我怎么就攤上這事召调。” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵唠叛,是天一觀的道長只嚣。 經(jīng)常有香客問我,道長艺沼,這世上最難降的妖魔是什么糯笙? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任店量,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘昼榛。我一直安慰自己,他們只是感情好拾徙,可當(dāng)我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布误续。 她就那樣靜靜地躺著,像睡著了一般定拟。 火紅的嫁衣襯著肌膚如雪于微。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天办素,我揣著相機與錄音角雷,去河邊找鬼。 笑死性穿,一個胖子當(dāng)著我的面吹牛勺三,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播需曾,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼吗坚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了呆万?” 一聲冷哼從身側(cè)響起商源,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎谋减,沒想到半個月后牡彻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡出爹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年庄吼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片严就。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡总寻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出梢为,到底是詐尸還是另有隱情渐行,我是刑警寧澤轰坊,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站祟印,受9級特大地震影響肴沫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蕴忆,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一樊零、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧孽文,春花似錦驻襟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至减牺,卻和暖如春豌习,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拔疚。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工肥隆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人稚失。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓栋艳,卻偏偏與公主長得像,于是被迫代替她去往敵國和親句各。 傳聞我的和親對象是個殘疾皇子吸占,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容