一、存在及需要解決的問題
一般在做後臺OA的時候會發現表單重複程式碼比較多,且邏輯基本一樣,每次新加一個表單都需要拷貝基本一致的程式碼結構,然後只是簡單地修改對應的欄位進行開發
二、預期結果
提取重複的表單邏輯形成通用的元件,通過約定的JSON資料結構配置生成表單
1、使用方法
<common-form :form-option="formOption" :is-reset-form-flag="isResetFormFlag"></common-form>
複製程式碼
接收的props:
isResetFormFlag:是否更新表單內容標誌,用於觸發更新表單的formModel
formOption:表單配置,下有詳細配置說明
isDisabled:表單是否可編輯
2、單一表單組配置
{
name: 'channel-form',
data: {},
items: [
{
label: '型別',
name: 'biz_type',
type: 'select',
dataList: [{
index: 1,
text: '業務部'
}]
}
],
rules: {
name: [{ required: true, message: '請輸入產品名稱', trigger: 'blur' }]
},
btnList: [{
text: '儲存',
type: 'primary',
onClick: this.commitForm
}]
}
複製程式碼
3、多表單組配置
formOption: {
name: 'channel-form',
data: {},
groups: [{
title: '',// 組標題
tips: ''// 組提示
items: [] // 組表單項,和單一組配置一致
}]
}
複製程式碼
三、實現邏輯
根據配置輸出不同的form-item,需要特殊處理的表單項通過jsx
由使用的地方自定義實現
什麼是JSX:cn.vuejs.org/v2/guide/re…
使用JSX原因:表單包含了大部分的選項,但是也有很多不確定的情況需要依賴外部自己實現,相對於template的方式jsx使用起來更加靈活
四、配置文件
節點 | 描述 | 型別 | 是否必須 | 備註 |
---|---|---|---|---|
name | 表單名 | String | 否 | 預設名 oa-form |
data | 表單資料 | Object | 否 | 用於編輯場景非同步請求的表單填充資料 |
groups | 表單組 | Array | 否 | groups 和 items 不應該同時存在,groups 中包含了items,如果groups為空取外部的items渲染,groups不為空僅渲染groups組內容 |
items | 表單項 | Array | 否 | 支援的type型別:輸入框:input、textarea;多選框:checkbox;單選框:radio;下拉選單:select |
rules | 表單校驗規則 | Object | 否 | 節點名需要與items配置的name一一對應 |
btnList | 按鈕列表 | Array | 否 | 會在回撥函式包含表單的資料及表單引用 |
六、VUE JSX 遇到的一些問題
v-model支援: babel-plugin-jsx-v-model
sync 修飾符寫法
visible={ this.dialogImgVisible } {...{on: {'update:visible': (val) => { this.dialogImgVisible = val }}}}
複製程式碼
七、部分實現程式碼
1、生成列表
generateList (itemObj) {
let itemEle = []
for (let index = 0; index < itemObj.dataList.length; index++) {
const item = itemObj.dataList[index]
switch (itemObj.type) {
// 下拉選單
case 'select':
itemEle.push(<el-option key={ item.index } label={ item.text } value={ item.index }></el-option>)
break
// 多選框
case 'checkbox':
itemEle.push(<el-checkbox label={ item.index }>{ item.text }</el-checkbox>)
break
// 單選框
case 'radio':
itemEle.push(<el-radio label={ item.index }>{ item.text }</el-radio>)
break
}
}
return itemEle
}
複製程式碼
2、生成下拉選單
generateSelect (item) {
return <el-select v-model={ this.formModel[item.name] } style={ item.style || this.defaultStyle }>{ this.generateList(item) }</el-select>
}
複製程式碼
備註:其他項實現類似
3、render函式
render (h) {
let ele = []
// 表單內容
if (this.isGroup) {
ele = this.generateGroup()
} else {
ele = this.generateFormItems(this.formOption.items)
}
// 按鈕列表
let btnListEle = []
this.formOption.btnList.forEach((btn) => {
btnListEle.push(<el-button type={ btn.type } on-click={ () => { btn.onClick(this.$refs[this.formName], this.formModel) } }>{ btn.text }</el-button>)
})
return (
<div class="oa-form-container">
<el-form ref={ this.formName } model={ this.formModel } rules={ this.formOption.rules } inline={ this.inline } disabled={ this.isDisabled } label-width={ this.formOption.labelWidth || '150px'}>
{ ele }
<el-form-item label-width={ this.isGroup ? '0' : '150px'}>{ btnListEle }</el-form-item>
</el-form>
</div>
)
}
複製程式碼
八、最後貼一個表格的封裝
<script>
export default {
props: {
// 表格列
columns: {
type: Array,
default: _ => { return [] }
},
// 表格資料
tableData: {
type: Array,
default: _ => { return [] }
},
// loading 標誌
loading: {
type: Boolean,
default: false
}
},
methods: {
sortChange (obj) {
this.$emit('sortChange', obj)
}
},
render () {
return (
<el-table border stripe v-loading={ this.loading } element-loading-text="拼命載入中" data={ this.tableData } on-sort-change={ obj => { this.sortChange(obj) } } style="width: 100%">
{
this.columns.map(columnObj => {
return <el-table-column prop={ columnObj.prop } label={ columnObj.label } sortable={ columnObj.sortable } width={ columnObj.width }
{...{
scopedSlots: {
default: scope => {
return columnObj.hasOwnProperty('render') ? columnObj.render(scope.index, scope.row) : scope.row[columnObj.prop]
}
}
}}
>
</el-table-column>
})
}
</el-table>
)
}
}
</script>
複製程式碼
1、使用方法
<common-table :columns="columns" :table-data="tableData" :loading="loading" @sort-change="sortChange"></common-table>
複製程式碼
2、columns 配置
{
label: '',
prop: '',
width: '100',
sortable: true
render: ()=>{}
}
複製程式碼
自定義配置渲染,傳入render函式,如果有render函式,優先使用render函式結果