vue 封装动态生成form表单和table表格组件

4 篇文章 0 订阅

背景

项目中经常遇到新加功能和之前功能类似,结构不变,只是名称和值变化,因此将常用的form表单检索和table表格展示进行封装,有助于提高开发效率和统一样式风格。
注:示例中使用iview框架,实际代码结构类似,供参考。

动态生成 form 表单组件

使用说明:

  • 引入文件并注册
  • 页面使用并传参,支持输入框、日期选择、下拉选择和查询按钮搜索项,搜索项后面可以通过插槽添加自定义内容
  • 组件暴露出的数据为 form 表单项最新数据

API:

form props

属性说明类型默认值
form表单项数据Object{}
formConfig表单项配置Array[]
inline表单项是否行内显示Booleantrue
labelWidth表单标签宽度Number100
labelPosition表单标签位置Stringleft

form events

事件名说明返回值
submit点击查询按钮触发formData,最新表单数据
form组件代码:
<template>
    <div class="form">
        <i-form
            ref="form"
            :model="formData"
            :inline="inline"
            :label-width="labelWidth"
            :label-position="labelPosition"
        >
            <i-form-item
                v-for="item in formConfig"
                :key="item.model"
                :label="item.label"
                :label-width="item.labelWidth"
            >
                <i-input
                    v-if="item.type === 'input'"
                    v-model="formData[item.model]"
                    :type="item.inputType ? item.inputType : 'text'"
                    clearable
                />

                <i-date-picker
                    v-if="item.type === 'daterange'"
                    v-model="formData[item.model]"
                    type="daterange"
                    format="yyyy-MM-dd"
                    :style="`
                        width: ${item.width ? item.width : 200}px
                    `"
                    @on-change="setDateRange(formData[item.model], item.model)"
                />

                <i-select
                    v-if="item.type === 'select'"
                    v-model="formData[item.model]"
                    clearable
                    placeholder="请选择"
                    :multiple="item.multiple"
                    :filterable="item.filterable"
                    :max-tag-count="item.max_tag_count"
                    style="width:100%;"
                >
                    <i-option
                        v-for="data in item.list"
                        :key="getSelectKeys(data, 'key')"
                        :value="getSelectKeys(data, 'key')"
                    >
                        {{ getSelectKeys(data, "value") }}
                    </i-option>
                </i-select>

                <slot name="item" />

                <i-button
                    v-if="item.type === 'confirm'"
                    type="primary"
                    :loading="item.isSearching"
                    @click="submit"
                >
                    查询
                </i-button>

                <i-button
                    v-if="item.type === 'reset'"
                    type="primary"
                    @click="reset"
                >
                    重置
                </i-button>

                <slot name="button" />
            </i-form-item>

            <slot name="form" />
        </i-form>
    </div>
</template>

<script>
export default {
    name: 'CommonForm',
    props: {
        // 表单项是否行内显示
        inline: {
            type: Boolean,
            default: true,
        },
        // 表单项配置
        formConfig: {
            type: Array,
            default: () => []
        },
        // 表单项数据
        form: {
            type: Object,
            default: () => {}
        },
        // 表单标签宽度
        labelWidth: {
            type: Number,
            default: 100,
        },
        // 表单标签位置,默认左侧
        labelPosition: {
            type: String,
            default: 'left',
        },
    },
    data() {
        return {
            formData: this.form,
            selectKeys: []
        };
    },
    mounted() {
        // 初始化设置formdata项的开始时间和结束时间
        this.formConfig
            .filter(item => item.type === 'daterange')
            .map(item => {
                this.setDateRange(this.formData[item.model], item.model);
            });
    },
    methods: {
        getSelectKeys(obj, type) {
            const key = Object.keys(obj);
            return type === 'key' ? obj[key[0]] : obj[key[1]];
        },
        // 选取日期后赋给 form 对应属性名
        setDateRange(date, model) {
            this.formData[`${model}_start`] = date[0];
            this.formData[`${model}_stop`] = date[1];
        },
        submit() {
            this.$emit('submit');
        },
        reset() {
            this.$refs.form.resetFields();
        }
    },
};
</script>

<style lang="less" scoped>
.form {
    display: flex;
    justify-content: flex-start;
    flex-wrap: wrap;

    .ivu-form-item {
        min-width: 19%;
        margin-bottom: 4px;

        /deep/ .ivu-input-with-suffix {
            padding: 4px;
        }
    }

    /deep/ .ivu-form {
        color: #333;
        width: 100%;
    }
}

@media screen and (max-width: 1300px){
    .ivu-form-item {
        width: 23%;
    };
}
</style>

form组件使用
<template>
    <div v-cloak>
        <CommonForm
            :form="form"
            :form-config="formConfig"
            :label-width="70"
            @submit="getList"
        />
    </div>
</template>

<script>
...
   data() {
       return {
       		isSearching: false, // // 是否查询中
           formConfig: [ // 表单配置
               { model: 'id', label: 'id', type: 'input'},
               {
                   model: 'status', //  搜索项参数名,和 form 中的参数名一致
                   label: '状态',  // 搜索项标签,即左侧文案
                   type: 'select', // 搜索项类型
                   multiple: true, // 是否支持多选
                   max_tag_count: 1, // 多选时最多显示多少个 tag
                   list: [], // select选择项列表
               },
               {
                   model: 'confirm', // 确认按钮
                   text: '查询', // 按钮文案
                   type: 'confirm',
                   label: '',
                   labelWidth: 0,
                   isSearching: this.isSearching
               },
           ],
           form: { // 检索参数
               id: '',
               page_number: 1,
               page_size: 10,
               time: [],
           },
       };
   },
};
</script>

动态生成 table表格组件

使用说明:

  • 引入文件并注册
  • 页面使用并传参,支持插槽,每列使用template可往插槽注入内容,目前组件中已封装根据状态显示为不同颜色的tag标签
  • 组件操作中,已封装查看和编辑功能

API:

table props

属性说明类型默认值
config表格项配置,包含表头数据和表格数据Object{}
editDisabled编辑为只读的条件配置项Object{}
editText编辑按钮文案String编辑

table events

事件名说明返回值
edit点击编辑按钮触发{row-当前行数据,isEdit-是否可编辑}
table组件:
<template>
    <div class="table">
        <i-table border :columns="config.header" :data="config.data">
            <template
                v-for="column in config.header"
                :slot="column.slot ? column.slot : ''"
                slot-scope="{row}"
            >
                <i-tag
                    v-if="row[column.slot] && row[column.slotName]"
                    :key="column.slot"
                    :color="
                        setStatusTagColor(
                            row[column.slot],
                            column.tagColorList,
                            column.slotDefaultColor
                        )
                    "
                >
                    {{ row[column.slotName] }}
                </i-tag>

                <slot :name="column.slot ? column.slot : ''" v-bind="row"></slot>
            </template>

            <template slot-scope="{row}" slot="action">
                <i-button type="primary" @click="edit(row, false)">查看</i-button>
                <i-button
                    type="error"
                    :disabled="
                        editDisabled
                        &&
                        editDisabled.disabledList.includes(+row[editDisabled.disabledColumn])"
                    @click="edit(row, true)"
                >
                    {{ editText }}
                </i-button>
            </template>
        </i-table>
    </div>
</template>

<script>
export default {
    name: 'CommonTable',
    props: {
        // 表单配置项
        config: {
            type: Object,
            default: () => {}
        },
        // 编辑为只读的条件配置项
        editDisabled: {
            type: Object,
            default: () => {}
        },
        // 编辑按钮文案
        editText: {
            type: String,
            default: '编辑'
        },
    },
    methods: {
        /*
        * 计算表格中标签展示颜色
        * @param {number|string} status 状态值
        * @param {array} tagColorList 标签颜色组合项
        * @param {string} defaultColor 不在标签颜色项时,默认标签颜色
        * @return {string} 返回str格式:标签颜色值
        *
        */
        setStatusTagColor(status, tagColorList = [], defaultColor) {
            const isExits = tagColorList.find(item => +item.status === +status);
            return isExits ? isExits.color : defaultColor;
        },
        edit(row, isEdit) {
            this.$emit('edit', row, isEdit);
        }
    },
};
</script>
table组件使用
<template>
    <div v-cloak>
        <CommonTable
            :config="tableConfig"
            :edit-disabled="editDisabledConfig"
            @edit="edit"
        />
        <i-page
            show-total
            :total="total"
            :page-size="form.page_size"
            @on-change="changepage"
        />
    </div>
</template>

<script>
...
    data() {
        return {
            tableConfig: {
                header: [
                    { title: '内容', key: 'name', tooltip: true },
                    {
                        title: '状态',
                        key: 'status',
                        slot: 'status', // 插槽名
                        slotName: 'status_name', // 展示的tag名称
                        tagColorList: [ // tag标签颜色集合
                            { status: 1, color: 'red' },
                            { status: 2, color: 'blue' },
                        ],
                        slotDefaultColor: 'red', // 不在tag标签颜色集合时,默认颜色
                    },
                    { title: '操作', key: 'action', slot: 'action', fixed: 'right' }
                ],
                // 表格数据,一般从接口获取
                data: [],
            },
            // 不可编辑条件
            editDisabledConfig: {
                disabledList: [120, 140], // 不可编辑数据集合
                disabledColumn: 'status', // 根据此列判断是否可编辑
            },
            // 总条数
            total: 0
        };
    },
};
</script>
  • 3
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值