Commit 35c37891c3192ed7fe12449960675de991579827

Authored by Aaron
1 parent 1416fdbe
Exists in master and in 1 other branch legacy

调整新式表单逻辑

examples/views/page/form-new/form-render.vue 0 → 100644
@@ -0,0 +1,81 @@ @@ -0,0 +1,81 @@
  1 +<template>
  2 + <!-- 在row上使用flex,防止表单组件大小不一导致错位 -->
  3 + <el-row type="flex" style="flex-wrap: wrap;" :class="contentClass || 'eagle-form__group-content'">
  4 + <template v-for="(item, index) in list">
  5 + <!-- 表单项有设置分组时 -->
  6 + <el-col v-if="item.group && item.list" :key="index" :span="item.group.span || 24">
  7 + <el-row type="flex" style="flex-wrap: wrap;">
  8 + <!-- 表单分组标题 -->
  9 + <el-col :class="titleClass || 'eagle-form__group-title'" v-if="item.group.title" :span="24">{{ item.group.title || item.group }}</el-col>
  10 + <!-- 递归本组件 -->
  11 + <form-render :title-class="titleClass" :list="item.list" :model="itemKey ? model[itemKey] || {} : model" @item-change="onItemChange" @form-item-change="onFormItemChange" :itemKey="item.group.key"></form-render>
  12 + </el-row>
  13 + </el-col>
  14 + <!-- 正常无分组表单项 -->
  15 + <el-col v-else :span="item.span || 12" :key="index">
  16 + <el-form-item :label="item.label" :label-width="item.labelWidth || '120px'" :prop="item.fullKey" :rules="item.rules">
  17 + <!-- 自定义组件 -->
  18 + <component :is="item.type" :value="itemValue(item)" @input="v => onInput({ value: v, item })"></component>
  19 + </el-form-item>
  20 + </el-col>
  21 + </template>
  22 + </el-row>
  23 +</template>
  24 +
  25 +<script>
  26 +export default {
  27 + name: 'form-render',
  28 + props: {
  29 + list: Array,
  30 + model: Object,
  31 + itemKey: String,
  32 + titleClass: String,
  33 + contentClass: String,
  34 + },
  35 + methods: {
  36 + /**
  37 + * @description 根据表单项的key查询该值
  38 + * @param {Object} item 表单项配置
  39 + * @returns {Any} 返回值
  40 + */
  41 + itemValue(item) {
  42 + if (this.itemKey) { // 如果存在itemKey,即当前项位于嵌套分组内,查询分组名下对应key的值
  43 + const groupItem = this.model[this.itemKey] || {};
  44 + return groupItem[item.key];
  45 + } else { // 否则即意味着不在分组内,直接查询model下对应key的值
  46 + return this.model[item.key];
  47 + }
  48 + },
  49 + /**
  50 + * @description 组件有值输入时的事件
  51 + * @param {Object} data { value => '组件值'; item => '表单项配置' }
  52 + */
  53 + onInput({ value, item }) {
  54 + if (this.itemKey) {
  55 + this.$emit('item-change', { [this.itemKey]: { ...this.model[this.itemKey], [item.key]: value } });
  56 + } else {
  57 + this.$emit('item-change', { [item.key]: value });
  58 + }
  59 + this.$emit('form-item-change', { [item.fullKey]: value });
  60 + },
  61 + /**
  62 + * @description 当表单项有改动时的事件
  63 + * @param {Any} 表单项值
  64 + */
  65 + onItemChange(value) {
  66 + if (this.itemKey) {
  67 + this.$emit('item-change', { [this.itemKey]: { ...this.model[this.itemKey], ...value } });
  68 + } else {
  69 + this.$emit('item-change', value);
  70 + }
  71 + },
  72 + /**
  73 + * @description 当表单项校验值有改动时的事件
  74 + * @param {Any} 表单项校验值
  75 + */
  76 + onFormItemChange(value) {
  77 + this.$emit('form-item-change', value);
  78 + }
  79 + }
  80 +}
  81 +</script>
examples/views/page/form-new/index.vue 0 → 100644
@@ -0,0 +1,103 @@ @@ -0,0 +1,103 @@
  1 +<template>
  2 + <el-form ref="form" size="small" :class="formClass" :model="formModel">
  3 + {{ formModel }}
  4 + <form-render :title-class="titleClass" :content-class="contentClass" :list="formList" :model="model" @item-change="onItemChange" @form-item-change="onFormItemChange"></form-render>
  5 + {{ list }}
  6 + </el-form>
  7 +</template>
  8 +
  9 +<script>
  10 +import FormRender from './form-render';
  11 +import { cloneDeep } from 'lodash';
  12 +
  13 +export default {
  14 + name: 'FormNew',
  15 + components: { FormRender },
  16 + props: {
  17 + value: Object,
  18 + list: Array,
  19 + formClass: String,
  20 + titleClass: String,
  21 + contentClass: String,
  22 + },
  23 + data() {
  24 + return {
  25 + model: {},
  26 + formModel: {},
  27 + }
  28 + },
  29 + watch: {
  30 + value(val = {}) {
  31 + this.model = val;
  32 + this.setFormModel(val)
  33 + },
  34 + },
  35 + computed: {
  36 + formList() {
  37 + // 深度克隆传入的列表,避免原始值被修改
  38 + const newList = cloneDeep(this.list);
  39 + // 生成列表值的全路径key,即列表项为对象时,对象内的key与上一级的key合并作为全路径key
  40 + const generateFullKey = (list, parentKey) => {
  41 + list.forEach(item => {
  42 + if (item.group && item.list) {
  43 + if (item.group.key) {
  44 + item.fullKey = `${parentKey ? `${parentKey}-${item.group.key}` : item.group.key}`;
  45 + } else {
  46 + item.fullKey = item.key;
  47 + }
  48 + generateFullKey(item.list, item.fullKey);
  49 + } else {
  50 + item.fullKey = `${parentKey ? `${parentKey}-${item.key}` : item.key}`;
  51 + }
  52 + });
  53 + };
  54 + generateFullKey(newList);
  55 + return newList;
  56 + }
  57 + },
  58 + methods: {
  59 + /**
  60 + * @description 表单项值变化
  61 + * @param {Object} item 表单项值对象
  62 + */
  63 + onItemChange(item) {
  64 + this.$emit('input', { ...this.model, ...item });
  65 + },
  66 + /**
  67 + * @description 表单相校验值变化
  68 + * @param {Object} item 表单项校验值对象
  69 + */
  70 + onFormItemChange(item) {
  71 + this.formModel = { ...this.formModel, ...item };
  72 + },
  73 + /**
  74 + * @description 校验表单
  75 + */
  76 + validate() {
  77 + this.$refs.form.validate(valid => {
  78 + this.$emit("validate", valid);
  79 + });
  80 + },
  81 + /**
  82 + * @description 根据表单值设置表单校验值
  83 + * @param {Object} value 表单值
  84 + */
  85 + setFormModel(value) {
  86 + let formModel = {};
  87 + // 递归深度解析表单值,将表单值扁平化为一层的对象并设置为表单校验值对象
  88 + const setFormModelValue = (list, parentKey) => {
  89 + list.forEach(item => {
  90 + item.fullKey = `${parentKey ? `${parentKey}-${item.key}` : item.key}`;
  91 + if (item.value instanceof Object) {
  92 + setFormModelValue(Object.keys(item.value).map(key => ({ key, value: item.value[key] })), item.fullKey);
  93 + } else {
  94 + formModel[item.fullKey] = item.value;
  95 + }
  96 + });
  97 + };
  98 + setFormModelValue(Object.keys(value).map(key => ({ key, value: value[key] })));
  99 + this.formModel = formModel;
  100 + }
  101 + }
  102 +}
  103 +</script>
examples/views/page/form/form-render.vue
@@ -1,56 +0,0 @@ @@ -1,56 +0,0 @@
1 -<template>  
2 - <el-row :gutter="15" type="flex" style="flex-wrap: wrap;">  
3 - <template v-for="(item, index) in list">  
4 - <el-col v-if="item.group && item.list" :key="index" :span="item.group.span || 24">  
5 - <el-row :gutter="15" type="flex" style="flex-wrap: wrap;">  
6 - <el-col v-if="item.group.title" :span="24">{{ item.group.title || item.group }}</el-col>  
7 - <form-render :list="item.list" :model="itemKey ? model[itemKey] || {} : model" @item-change="onItemChange" @form-item-change="onFormItemChange" :itemKey="item.group.key"></form-render>  
8 - </el-row>  
9 - </el-col>  
10 - <el-col v-else :span="item.span || 12" :key="index">  
11 - <el-form-item :label="item.label" :label-width="item.labelWidth || '120px'" :prop="item.fullKey" :rules="item.rules">  
12 - <component :is="item.type" :value="itemValue({ item })" @input="v => handleInput({ value: v, item })"></component>  
13 - </el-form-item>  
14 - </el-col>  
15 - </template>  
16 - </el-row>  
17 -</template>  
18 -  
19 -<script>  
20 -export default {  
21 - name: 'form-render',  
22 - props: {  
23 - list: Array,  
24 - model: Object,  
25 - itemKey: String,  
26 - },  
27 - methods: {  
28 - itemValue({ item }) {  
29 - if (this.itemKey) {  
30 - const groupItem = this.model[this.itemKey] || {};  
31 - return groupItem[item.key];  
32 - } else {  
33 - return this.model[item.key];  
34 - }  
35 - },  
36 - handleInput({ value, item }) {  
37 - if (this.itemKey) {  
38 - this.$emit('item-change', { [this.itemKey]: { ...this.model[this.itemKey], [item.key]: value } });  
39 - } else {  
40 - this.$emit('item-change', { [item.key]: value });  
41 - }  
42 - this.$emit('form-item-change', { [item.fullKey]: value });  
43 - },  
44 - onItemChange(value) {  
45 - if (this.itemKey) {  
46 - this.$emit('item-change', { [this.itemKey]: { ...this.model[this.itemKey], ...value } });  
47 - } else {  
48 - this.$emit('item-change', value);  
49 - }  
50 - },  
51 - onFormItemChange(value) {  
52 - this.$emit('form-item-change', value);  
53 - }  
54 - }  
55 -}  
56 -</script>  
57 \ No newline at end of file 0 \ No newline at end of file
examples/views/page/form/index.vue
@@ -1,86 +0,0 @@ @@ -1,86 +0,0 @@
1 -<template>  
2 - <el-form ref="form" size="small" :model="formModel">  
3 - {{ formModel }}  
4 - <form-render :list="formList" :model="model" @item-change="onItemChange" @form-item-change="onFormItemChange"></form-render>  
5 - </el-form>  
6 -</template>  
7 -  
8 -<script>  
9 -import FormRender from './form-render';  
10 -  
11 -export default {  
12 - components: { FormRender },  
13 - props: {  
14 - value: Object,  
15 - list: Array,  
16 - },  
17 - data() {  
18 - return {  
19 - model: {},  
20 - formModel: {}  
21 - }  
22 - },  
23 - watch: {  
24 - value(val) {  
25 - const data = val || {};  
26 - this.model = data;  
27 - let formModel = {};  
28 - const setFormModelValue = (list, parentKey) => {  
29 - list.forEach(item => {  
30 - item.fullKey = `${parentKey ? `${parentKey}-${item.key}` : item.key}`;  
31 - if (item.value instanceof Object) {  
32 - setFormModelValue(Object.keys(item.value).map(key => ({ key, value: item.value[key] })), item.fullKey);  
33 - } else {  
34 - if (item.fullKey) {  
35 - formModel[item.fullKey] = item.value;  
36 - }  
37 - }  
38 - });  
39 - };  
40 - setFormModelValue(Object.keys(data).map(key => ({ key, value: data[key] })));  
41 - this.formModel = formModel;  
42 - },  
43 - },  
44 - computed: {  
45 - formList() {  
46 - const newList = [...new Set(this.list)]  
47 - const generateFullKey = (list, parentKey) => {  
48 - list.forEach(item => {  
49 - if (item.group && item.list) {  
50 - if (item.group.key) {  
51 - item.fullKey = `${parentKey ? `${parentKey}-${item.group.key}` : item.group.key}`;  
52 - } else {  
53 - item.fullKey = item.key;  
54 - }  
55 - generateFullKey(item.list, item.fullKey);  
56 - } else {  
57 - item.fullKey = `${parentKey ? `${parentKey}-${item.key}` : item.key}`;  
58 - }  
59 - });  
60 - };  
61 - generateFullKey(newList);  
62 - return newList;  
63 - }  
64 - },  
65 - methods: {  
66 - // 表单项值变化  
67 - onItemChange(item) {  
68 - this.$emit('input', { ...this.model, ...item });  
69 - },  
70 - // 表单相校验值变化  
71 - onFormItemChange(item) {  
72 - this.formModel = { ...this.formModel, ...item };  
73 - },  
74 - // 校验表单  
75 - validate() {  
76 - this.$refs.form.validate(valid => {  
77 - this.$emit("validate", valid);  
78 - });  
79 - },  
80 - }  
81 -}  
82 -</script>  
83 -  
84 -<style>  
85 -  
86 -</style>  
87 \ No newline at end of file 0 \ No newline at end of file
examples/views/page/other.vue
  1 +<style>
  2 +.custom-form {
  3 + background: #cfc;
  4 +}
  5 +.custom-title {
  6 + background: #ccf;
  7 +}
  8 +.custom-content {
  9 + background: #fcc;
  10 +}
  11 +</style>
  12 +
1 <template> 13 <template>
2 <div> 14 <div>
3 <p>这是一个非markdown页面</p> 15 <p>这是一个非markdown页面</p>
4 <pre>{{ model }}</pre> 16 <pre>{{ model }}</pre>
5 <el-button size="mini" @click="handleGetValue">校验</el-button> 17 <el-button size="mini" @click="handleGetValue">校验</el-button>
6 - <eg-form ref="form" v-model="model" :list="option.list" @validate="onValidate"></eg-form> 18 + <eg-form ref="form" v-model="model" :list="option.list" @validate="onValidate" form-class="custom-form" title-class="custom-title" content-class="custom-content"></eg-form>
7 </div> 19 </div>
8 </template> 20 </template>
9 21
10 <script> 22 <script>
11 -import EgForm from './form'; 23 +import EgForm from './form-new';
12 24
13 export default { 25 export default {
14 name: 'other', 26 name: 'other',
@@ -95,4 +107,4 @@ export default { @@ -95,4 +107,4 @@ export default {
95 } 107 }
96 } 108 }
97 } 109 }
98 -</script>  
99 \ No newline at end of file 110 \ No newline at end of file
  111 +</script>