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 @@
  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 @@
  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   -<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 0 \ No newline at end of file
examples/views/page/form/index.vue
... ... @@ -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 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 13 <template>
2 14 <div>
3 15 <p>这是一个非markdown页面</p>
4 16 <pre>{{ model }}</pre>
5 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 19 </div>
8 20 </template>
9 21  
10 22 <script>
11   -import EgForm from './form';
  23 +import EgForm from './form-new';
12 24  
13 25 export default {
14 26 name: 'other',
... ... @@ -95,4 +107,4 @@ export default {
95 107 }
96 108 }
97 109 }
98   -</script>
99 110 \ No newline at end of file
  111 +</script>
... ...