抽離配置,幾分鐘快速建立和修改表單

本文志在經過合理的配置,能夠增長或減小一行代碼,就能輕鬆增長表單項。javascript

用element-ui的表單組件的時候,仍是有點不順手。跟用表格的感受差不離,但優雅的使用 element-ui 中的 table 組件很棒的解決了這個問題。模仿這個,本身也簡單的抽離了表單的配置。不過這並不必定適合全部的表單,具體狀況具體使用吧。html

邏輯是:vue

  1. 將el-form封裝成一個組件
  2. 將表單的配置項傳給這個組件,生成相應的表單。

沒有封裝前的form

首先看下,帶有校驗功能的form表單多數是這樣,這裏簡單化表單只剩兩個表單項。java

原始表單

<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
  <el-form-item label="活動名稱" prop="name">
    <el-input v-model="ruleForm.name"></el-input>
  </el-form-item>
  <el-form-item label="活動區域" prop="region">
    <el-select v-model="ruleForm.region" placeholder="請選擇活動區域">
      <el-option label="區域一" value="shanghai"></el-option>
      <el-option label="區域二" value="beijing"></el-option>
    </el-select>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" @click="submitForm('ruleForm')">當即建立</el-button>
    <el-button @click="resetForm('ruleForm')">重置</el-button>
  </el-form-item>
</el-form>
<script> export default { data() { return { ruleForm: { name: '', region: '', }, rules: { name: [ { required: true, message: '請輸入活動名稱', trigger: 'blur' }, { min: 3, max: 5, message: '長度在 3 到 5 個字符', trigger: 'blur' } ], region: [ { required: true, message: '請選擇活動區域', trigger: 'change' } ] } }; }, methods: { submitForm(formName) { this.$refs[formName].validate((valid) => { if (valid) { alert('submit!'); } else { console.log('error submit!!'); return false; } }); }, } } </script>
複製代碼

通常的表單具有的條件有如下:element-ui

  • el-form自己綁定一個model,{name:'',region:''},裏面的屬性就是每一個表單項將要綁定的
  • el-form上有個方便校驗規則的屬性rules,{name: [ { required: true, message: '請輸入活動名稱', trigger: 'blur' }], region: [ { required: true, message: '請選擇活動區域', trigger: 'change' } ]}
  • el-form上還有ref,在點擊提交表單的時候也是用於校驗
  • el-form上還有其餘屬性的設置,label寬度,對齊方式之類的
  • el-form-item每一個必有label屬性和prop屬性,prop就是model的鍵名,各個表單元素上面有各自的配置

先抽離表單配置

由此,總結一個表單的配置項:model,rules,ref,attrsOther。
可是通常咱們接到一個表單的需求,一般關注點是,這個表單項的label是什麼,什麼類型的,校驗方式如何,是否有默認值,有哪些選項之類的的等等,由此,表單配置項我是這樣的:post

let formConfig = {
  // category就是element裏要用到的組件名,這裏不能用type和component,後期要用,想不到合適的詞就暫且用這個了
  name:{label:'活動名稱',category:'input',placeholder: `請輸入活動名稱`,default:'xxx',rules: [ { required: true, message: `活動名稱不能爲空`, trigger: "blur" } ]},
}

複製代碼

後期若是須要增長一個表單項,或者修改一些配置,直接修改這裏便可,再也不須要去各個地方修改。ui

具體實現組件的操做

先實現一個簡單的表單:this

表單

其實這個組件的封裝須要的數據很明瞭,最重要的是上面的formConfig,表單將會根據這個配置自動生成。spa

組件拿到formConfig以後,首先要把modelrules抽離出來,而後循環formConfig便可。code

1. 實現組件

<!-- 假設組件就叫 EnhancedForm.vue -->
<template>
  <!-- v-bind會自動將form的配置屬性賦值過來,特別棒的一個指令 -->
  <el-form :model="form.props" :rules="form.rules" >
    <!-- 表單的每項都是一個組件,用法參照 https://element.eleme.cn/#/zh-CN/component/form -->
    <el-form-item v-for="(config, prop) in form.configs" :label="config.label" :key="prop" :prop="prop">
      <!-- 若是使用的組件是el-input纔會是這樣,每一個表單項的配置可能不同,但不要緊,有v-bind -->
      <el-input v-if="config.category === 'input'" v-model="form.props[prop]" v-bind="config">
      </el-input>
      <!-- 若是使用的組件是el-select纔會是這樣 -->
      <el-select v-if="config.category === 'select'" v-model="form.props[prop]" >
        <el-option v-for="item in config.options" :key="item.value" :value="item.value" :label="item.label" ></el-option>
      </el-select>
    </el-form-item>
  </el-form>
</template>
<script> export default { props: ['formConfig'], data () { let form = { configs: this.formConfig, // el-form的model的值 props: {}, rules: {} } Object.keys(this.formConfig).forEach(prop => { // 這裏若是設置了默認項就是默認值,沒有就是undefined form.props[prop] = this.formConfig[prop].default form.rules[prop] = this.formConfig[prop].rules }) return { form } } } </script>

複製代碼

2. 引用組件

使用的話,以下:

<!-- 假設是views/Form.vue -->
<template>
  <div>
    <enhanced-form :form-config="formConfig"></enhanced-form>
  </div>
</template>
<script> import EnhancedForm from '../components/EnhancedForm.vue' export default { components: { EnhancedForm }, data () { let formConfig = { // category就是element裏要用到的組件名,這裏不能用type和component,後期要用,想不到合適的詞就暫且用這個了 name: { label: '活動名稱', category: 'input', placeholder: `請輸入活動名稱`, rules: [ { required: true, message: `活動名稱不能爲空`, trigger: 'blur' } ], style: { width: '300px' } }, region: { label: '活動區域', category: 'select', default: 2, options: [{ label: '南京', value: 1 }, { label: '北京', value: 2 }], rules: [ { required: true, message: `請選擇活動區域`, trigger: 'change' } ] } } return { formConfig } } } </script>

複製代碼

3. 增長表單項

上面的其實已經實現了,但此時若是忽然要增長表單項,好比想增長一個密碼,很簡單,直接修改formConfig便可,是否是很方便~

// <!-- 假設是views/Form.vue -->
    let formConfig = {
      // ...
      // 這裏是密碼因此多了showPassword:true,其餘表單項也是同樣的,根據需求自由配置
      password: { label: '密碼', category: 'input',showPassword:true, placeholder: `請輸入密碼`, rules: [ { required: true, message: `密碼不能爲空`, trigger: 'blur' } ], style: { width: '300px' } }
    }
複製代碼

效果

父組件怎麼拿到form的全部數據

其實這個簡單,父組件在enhanced-form標籤上設置ref的屬性,而後經過this.$refs.xx.$data.form.props就能夠拿到全部表單項的數據(其實能夠經過ref拿到子組件全部的信息~~):

<!-- 假設是views/Form.vue -->
<template>
  <div>
    <enhanced-form ref="demoForm" :form-config="formConfig"></enhanced-form>
    <el-button @click="handleClick"> 點吖 </el-button>
  </div>
</template>
<script> import EnhancedForm from '../components/EnhancedForm.vue' export default { components: { EnhancedForm }, // data () { ....}, methods: { handleClick () { console.log(this.$refs.demoForm.$data.form.props) } } } </script>
複製代碼

效果

咦,自動檢測呢

嘿,自動檢測還沒實現呢!其實也不難吶,這裏由於須要ref,因此,在傳入子組件的時候,除了有formConfig,能夠增長formAttr是給form增長自身的屬性,好比ref/labelWidth/labelPosition等等

<!-- EnhancedForm.vue -->
<el-form :model="form.props" :rules="form.rules" v-bind="form.attrs">
<script> props: ['formConfig', 'formAttr'], data () { let form = { // ... attrs: this.formAttr, } </script>
複製代碼
<!-- Form.vue -->
<enhanced-form ref="demoForm" :form-config="formConfig" :form-attr="formAttr"></enhanced-form>
<script> data(){ // ... let formAttr = { ref: 'hiForm', labelWidth: '80px' } return { formConfig, formAttr } } handleClick () { console.log(this.$refs.demoForm.$data.form.props) this.$refs.demoForm.$refs[this.formAttr.ref].validate(valid => { console.log(valid) }) } </script>

複製代碼

效果圖

特殊需求的表單項,用slot

上面都是正常的,若是有特殊需求的,能夠插入slot和component。這裏演示slot

<!-- EnhancedForm.vue -->
    <template v-for="(config, prop) in form.configs" >
      <slot v-if="config.slotName" :name="config.slotName" v-bind:form="form" v-bind:config="config"></slot>
      <!-- 表單的每項都是一個組件,用法參照 https://element.eleme.cn/#/zh-CN/component/form -->
      <el-form-item v-else :label="config.label" :key="prop" :prop="prop">

複製代碼
<enhanced-form ref="demoForm" :form-config="formConfig" :form-attr="formAttr">
      <template v-slot:desc="{config,form}">
        <el-form-item :label="config.label" prop="desc">
          <el-input v-model="form.props.desc" v-bind="config"></el-input>
        </el-form-item>
      </template>
    </enhanced-form>
<script> let formConfig = { // ... // slotName有這個屬性的表示是slot,注意這裏不能叫slot否則後期v-bind會衝突。 desc: { slotName: 'desc', label: '評價', category: 'input', placeholder: `請輸入評價`, rules: [ { required: true, message: `評價不能爲空`, trigger: 'blur' } ], style: { width: '300px' } } } </script>
複製代碼

效果圖

昇華

實際項目中,固然不可能只是input和select,但觸類旁通,其餘也同樣的配置。這裏是我本身的配置,還有一部分並未放進去,根據需求本身能夠再修改,如下僅供參考。

<template>
  <!-- v-bind會自動將form的配置屬性賦值過來,特別棒的一個指令 -->
  <el-form :model="form.props" :rules="form.rules" v-bind="form.attrs">
    <template v-for="(config, prop) in form.configs" >
      <slot v-if="config.slotName" :name="config.slotName" v-bind:form="form" v-bind:config="config"></slot>
      <!-- 表單的每項都是一個組件,用法參照 https://element.eleme.cn/#/zh-CN/component/form -->
      <el-form-item v-else :label="config.label" :key="prop" :prop="prop">
        <!-- 文本框 類-->
        <component v-if=" config.category === 'input' || config.category === 'input-number' || config.category === 'time-picker' || config.category === 'date-picker' " :is="'el-' + config.category" v-model="form.props[prop]" :key="config.component" v-bind="config" ></component>
        <!-- 選擇框類 -->
        <el-radio-group v-if="config.category === 'radio-group'" v-model="form.props[prop]" >
          <el-radio v-for="item in config.options" :key="item.value" :label="item.value" >{{ item.label }}</el-radio >
        </el-radio-group>
        <el-checkbox-group v-if="config.category === 'checkbox-group'" v-model="form.props[prop]" >
          <el-checkbox v-for="item in config.options" :key="item.value" :label="item.value" >{{ item.label }}</el-checkbox >
        </el-checkbox-group>
        <el-select v-if="config.category === 'select'" v-model="form.props[prop]" >
          <el-option v-for="item in config.options" :key="item.value" :value="item.value" :label="item.label" ></el-option>
        </el-select>
      </el-form-item>
    </template>
  </el-form>
</template>
<script> export default { props: ['formConfig', 'formAttr'], data () { let form = { configs: this.formConfig, attrs: this.formAttr, // el-form的model的值 props: {}, rules: {} } Object.keys(this.formConfig).forEach(prop => { // 這裏若是設置了默認項就是默認值,沒有就是undefined form.props[prop] = this.formConfig[prop].default form.rules[prop] = this.formConfig[prop].rules }) return { form } } } </script>

複製代碼
相關文章
相關標籤/搜索