Skip to content

扩展组件

自定义组件可以被集成到设计器中,用于扩展功能。以下是如何创建和使用自定义组件的详细说明。

渲染器文档中可以查看内置表单组件及其所有可配置参数。

自定义表单组件可查阅自定义表单组件的开发规范与标准要求。

源码中可以查看更多组件拖拽配置规则,供您开发参考。

扩展组件教程

手把手教你创建一个 Title 标题组件,可在表单中灵活显示各类标题文本。

component1

1. 封装组件

新建 Title.vue 文件,开发标题组件的功能样式。

vue
<template>
    <div class="_fc-title" :class="size || 'h2'" :style="textStyle">
        {{ title }}
    </div>
</template>
<script>
    import {defineComponent} from 'vue';
    export default defineComponent({
        name: 'FcTitle',
        data() {
            return {};
        },
        props: {
            title: String,
            size: String,
            align: String,
        },
        computed: {
            textStyle() {
                return {
                    textAlign: this.align || 'left',
                }
            }
        }
    });
</script>
<style>
    ._fc-title {
        width: 100%;
        font-size: 16px;
        font-weight: 600;
        margin-top: 1em;
        margin-bottom: 16px;
    }


._fc-title.h1, ._fc-title.h2 {
        padding-bottom: .3em;
        border-bottom: 1px solid #eee
    }


._fc-title.h1 {
        font-size: 32px;
        line-height: 1.2
    }


._fc-title.h2 {
        font-size: 24px;
        line-height: 1.225
    }


._fc-title.h3 {
        font-size: 20px;
        line-height: 1.43
    }


._fc-title.h4 {
        font-size: 16px;
    }


._fc-title.h5 {
        font-size: 14px;
    }


._fc-title.h6 {
        font-size: 12px;
    }
</style>

2. 挂载组件

在 main.js 中挂载 Title 组件

ts
import Title from 'Title.vue'
import FcDesigner from '/path/to/fcDesignerPro/dist/index.es.js'


FcDesigner.component('Title', Title);
//或者通过 app 全局挂载
app.component('Title', Title);

或者在组件中挂载 Title 组件

vue
<script>
    import {defineComponent} from 'vue'; 
    import Title from 'Title.vue';
    import FcDesigner from '/path/to/fcDesignerPro/dist/index.es.js'
    export default defineComponent({
        mounted() {
            FcDesigner.component('Title', Title);
        }
    });
</script>

3.定义拖拽规则

定义 Title 组件的拖拽规则

js
const titleDragRule = {
    menu: 'aide',
    icon: 'icon-title',
    label: '标题',
    //唯一 ID
    name: 'title',
    //组件可以配置的事件
    event: ['click'],
    rule() {
        //组件的渲染规则
        return {
            //组件的名称, 与上一步是对应
            type: 'Title',
            props: {
                title: '自定义标题',
            },
        };
    },
    props() {
        //组件右侧的配置项,与组件中的 props 对应
        return [
            {type: 'input', field: 'title', title: '标题'},
            {
                type: 'select',
                field: 'size',
                title: '尺寸',
                //默认值
                value: 'H2',
                options: [1, 2, 3, 4, 5, 6].map(k => {
                    return {label: 'H' + k, value: 'h' + k};
                })
            }, {
                type: 'select',
                field: 'align',
                title: '位置',
                options: [
                    {label: '左侧', value: 'left'},
                    {label: '居中', value: 'center'},
                    {label: '右侧', value: 'right'}
                ]
        }];
    }
};

渲染器文档中可以查看内置表单组件及其所有可配置参数。

component2

根据 props 函数定义的规则,自动生成组件右侧的配置面板选项。

4.导入拖拽规则

定义好拖拽规则后,需要将其挂载到设计器中。

js
// 假设这是你的 Vue 组件
export default {
    mounted() {
        // 挂载拖拽规则
        this.$refs.designer.addComponent(titleDragRule);
    }
};

通过以上步骤,您可以将自定义组件与设计器集成,并为其定义拖拽行为和属性配置,使其在设计器中成为可用的组件。这不仅提高了设计器的灵活性,还可以根据具体需求扩展其功能。

扩展表单组件教程

自定义表单组件可以用来实现业务特定的表单控件。下面将介绍如何定义和使用自定义表单组件,包括如何导入、挂载组件及设置其拖拽规则。

自定义表单组件可查阅自定义表单组件的开发规范与标准要求。

1. 封装组件

手把手教你基于 Element Plus 的 Input 组件,开发定制化的新输入框组件。

新建 Input.vue 文件,开发输入框组件的功能。

vue
<template>
    <el-input :disabled="disabled" :modelValue="modelValue" @update:modelValue="handleChange" v-bind="$attrs">
        <!--自定义组件的插槽-->
        <template #prepend>Http://</template>
    </el-input>
</template>
<script>
    import {defineComponent} from 'vue';
    export default defineComponent({
        name: 'FcInput',
        data() {
            return {};
        },
        emits: ['update:modelValue', 'change'],
        props: {
            //获取表单数据
            modelValue: String,
            //支持表单禁用功能
            disabled: Boolean
        },
        methods: {
            //更新表单数据
            handleChange(val) {
                this.$emit('update:modelValue', val);
                //触发 change 事件
                this.$emit('change', val);
            }
        }
    });
</script>

使用 v-bind="$attrs" 可自动透传所有配置项到 el-input 组件,无需重复定义即可继承全部属性。

2. 挂载组件

在 main.js 中挂载 Input 组件

ts
import Input from 'Input.vue'
import FcDesigner from '/path/to/fcDesignerPro/dist/index.es.js'


FcDesigner.component('FcInput', Input);
//或者通过 app 全局挂载
app.component('FcInput', Input);

或者在组件中挂载 Title 组件

vue
<script>
    import {defineComponent} from 'vue'; 
    import Input from 'Input.vue';
    import FcDesigner from '/path/to/fcDesignerPro/dist/index.es.js'
    export default defineComponent({
        mounted() {
            FcDesigner.component('FcTitle', Input);
        }
    });
</script>

3.定义拖拽规则

定义 Input 组件的拖拽规则

ts
import uniqueId from '@form-create/utils/lib/unique';
const InputDragRule = {
    menu: 'main',
    icon: 'icon-input',
    label: '自定义输入框',
    //唯一 ID
    name: 'FcInput',
    //表单组件标识
    input: true,
    //组件的事件
    event: ['blur', 'focus', 'change', 'input', 'clear'],
    validate: ['string', 'url', 'email'],
    rule({t}) {
        return {
            //组件的名称, 与上一步是对应
            type: 'FcInput',
            field: uniqueId(),
            title: '自定义输入框',
            info: '',
            $required: false,
            props: {}
        };
    },
    props() {
        return [
            {
                type: 'switch',
                title: '禁用',
                field: 'disabled'
            },
            {
                type: 'switch',
                title: '清空',
                field: 'clearable'
            },
            {
                type: 'input',
                title: '占位文字',
                field: 'placeholder'
            },
        ];
    }
};
export default InputDragRule;

渲染器文档中可以查看内置表单组件及其所有可配置参数。

注意: 调用 uniqueId 方法需先安装 @form-create/utils 包,或自定义实现以字母开头的唯一ID生成逻辑(禁止包含符号)。

sh
npm install @form-create/utils@^3

4.导入拖拽规则

定义好拖拽规则后,需要将其挂载到设计器中。

js
// 假设这是你的 Vue 组件
export default {
    mounted() {
        // 挂载拖拽规则
        this.$refs.designer.addComponent(InputDragRule);
    }
};

props 配置名称映射规则

在组件配置规则(props)方法中,如果 fieldformCreate 开头,系统将自动修改规则中对应的字段。这使得开发者可以通过统一的方式来定义和映射组件的配置。

字段说明
type修改rule.props.type字段
options>label修改rule.props.options.label字段
formCreateStyle修改rule.style字段
formCreateStyle>width修改rule.style.width字段
formCreateChild修改rule.children[0]

例如:

js
{
    props() {
        return [
            {
                type: 'switch',
                title: '禁用',
                //配置名称, 修改 rule.props.disabled
                field: 'disabled'
            },
            {
                type: 'switch',
                title: '清空',
                //配置名称, 修改 rule.props.clearable
                field: 'clearable'
            },
            {
                type: 'input',
                title: '占位文字',
                //配置名称, 修改 rule.props.placeholder
                field: 'placeholder'
            },
        ];
    }
}

更多示例

限制只能拖入1个

ts
const InputDragRule = {
    menu: 'main',
    icon: 'icon-input',
    label: '自定义输入框',
    name: 'FcInput',
    //只能拖入1个
    only: true,
    //...
}

行内组件

行内组件的宽度不会自动撑开100%

ts
const InputDragRule = {
    menu: 'main',
    icon: 'icon-input',
    label: '自定义输入框',
    name: 'FcInput',
    //行内组件标识
    inline: true,
    //...
}

定义组件需要用到的多语言ID

ts
const InputDragRule = {
    menu: 'subform',
    icon: 'icon-table-form',
    label: '表格表单',
    name: 'tableForm',
    input: true,
    mask: false,
    subForm: 'array',
    //多语言 ID
    languageKey: ['add', 'operation', 'dataEmpty'],
    //...
}

禁止配置组件样式

ts
const InputDragRule = {
    menu: 'main',
    icon: 'icon-input',
    label: '自定义输入框',
    name: 'FcInput',
    //禁止配置组件样式
    style: false,
    //...
}

转换组件规则

例如 group 组件的子表单规则实际存储在 props.rule 中,但为便于可视化设计会展示在 children 字段,这个时候就需要进行双向数据转换适配。

ts
const InputDragRule = {
    menu: 'main',
    icon: 'icon-input',
    label: '自定义输入框',
    name: 'FcInput',
    //加载设计器渲染规则时
    loadRule(rule) {
        rule.children = rule.props.rule || [];
        rule.type = 'FcRow';
        delete rule.props.rule;
    },
    //导出最终渲染规则时触发
    parseRule(rule) {
        rule.props.rule = rule.children;
        rule.type = 'group';
        delete rule.children;
        delete rule.props.mode;
    },
    //...
}

数据结构

ts
interface DragRule {
    //组件id,不能重复
    name: string;
    //组件的名称
    label: string;
    //组件的图标
    icon: string;
    //插入的分类
    menu?: MenuName;
    //是否支持样式配置
    style?: boolean;
    //是否是行内组件
    inline?: boolean;
    //是否是表单组件
    input?: boolean;
    //如果是子表单组件,需要定义`value`的类型
    subForm?: 'object' | 'array';
    //可拖入的组件列表
    allowDrag?: AllowDrag;
    //不可拖入的组件列表
    denyDrag?: DenyDrag;
    //组件,不建议使用
    component?: Component;
    //渲染子组件的列表
    subRender: ({h, resolveComponent, subRule, rule}: {
        h: typeof H<any>,
        resolveComponent: typeof ResolveComponent,
        subRule: Rule,
        rule: Rule
    }) => Array<{
        label: string;
        vnode: VNode
    }>;
    //配置组件条件选择方式
    condition: conditionComponentType | ((rule: Rule) => ({
        //组件类型
        type: conditionComponentType;
        //选择项
        options?: any[];
        //组件类型
        props?: Object;
    }));
    //多语言配置项
    languageKey: string[];
    //表单全局配置
    formOptions?: {
        globalClass?: GlobalClass;
        globalVariable?: GlobalVariable;
        globalData?: GlobalData;
        globalEvent?: GlobalEvent;
        language?: Object;
        style?: string;
    } | string;
    //组件的生成规则
    rule(arg: { t: t }): Rule;
    //组件属性配置的规则
    props(rule: Rule, arg: { t: t, api: Api }): Rule[];
    //导出规则时通过这个方法转成最终规则
    parseRule?: (rule: Rule) => void;
    //导入规则时通过这个方法转成设计器中的渲染规则
    loadRule?: (rule: Rule) => void;
    //当props中的字段变化时触发
    watch?: {
        [key: string]: (arg: { value: any, rule: Rule, api: Api, field: string }) => void;
    };
    //是否有配套的子组件,例如Row和Col
    children?: string;
    //初始化时渲染几个子组件
    childrenLen?: number;
    //当前组件的操作容器是否显示在组件内部,为false时操作容器包裹当前组件
    inside?: true | boolean;
    //是否可以拖入其他组件到当前组件内部
    drag?: true | string | boolean;
    //是否显示拖拽按钮
    dragBtn?: false | boolean;
    //控制操作操作按钮是否显示,显示哪些
    handleBtn?: true | boolean | Array<'create' | 'copy' | 'addChild' | 'delete'>;
    //隐藏基础配置中的字段
    hiddenBaseField?: string[];
    //是否显示遮罩, 避免对组件操作. 建议有子组件时为true,其他为false
    mask?: false | boolean;
    //是否只能拖入一个
    only?: boolean;
    //是否生成name
    aide?: boolean;
    //当前组件的插槽
    easySlots?: Array<string| {
        //插槽名称
        value: string;
        //插槽简介
        label?: string;
        //类型
        type?: 'icon' | 'text'
    }>;
    //当前组件支持的事件
    event?: string[];
    //当前组件`value`的数据类型
    validate?: string[] | boolean;
}