低代码页面颜值&布局天花板!Unione Form Editor 自定义 Card 卡片组件源码解析

为什么你的低代码页面总是又乱又丑?问题出在布局组件
很多人搭建低代码业务系统,只关注表单输入、数据填报,忽略了页面布局与视觉分层。
把所有字段直接平铺堆砌,最终页面杂乱无章、信息无分区、重点不突出,不管是后台管理、生产台账还是工单系统,整体观感极其廉价,用户体验极差。
市面上多数开源低代码的卡片组件都存在短板:样式固化、不支持折叠、无标签页模式、无法自定义头部按钮、适配性差,根本满足不了企业级页面排版需求。
今天给大家拆解 Unione Form Editor 自研 Card 卡片布局组件,完整开源源码、双模式布局、可折叠+自定义头部+标签页切换,是搭建精致、规整、企业级低代码页面的核心布局组件。
Unione Card 卡片组件|核心能力亮点
这不仅仅是一个简单的卡片容器,更是一套完整的低代码页面布局解决方案:
✅ 双布局模式:支持常规普通卡片 + Tabs 标签页卡片,一键切换
✅自适应折叠功能:可开启伸缩折叠,隐藏冗余内容,页面更简洁
✅ 高度自定义头部:支持图标、标题、标识色块、自定义更多按钮
✅ 标签页拓展能力:自定义Tab图标、头部拓展按钮,适配多模块分区
✅ 引擎深度适配:原生对接表单引擎,内部可嵌套任意表单组件
✅ 样式精细化定制:支持圆形/方形/线条标识,视觉分层更清晰
✅ 零门槛接入:全局注册即用,和官方内置组件体验完全一致
一、完整源码逐段核心解析(Vue3 + TS 企业级写法)
1. 模板层:多层插槽+双模式适配,结构高度灵活
模板核心设计:融合常规卡片、标签页卡片双模式,拆分头部标题栏、拓展按钮区、自定义标签、内容容器多层结构,同时支持折叠展开交互,适配所有业务页面布局场景。
<template>
<Widget :class="['unione-layout', 'unione-card', open ? 'open' : 'close']" :wid="widgetObj.wid" :engine="props.engine">
<a-card :tab-list="tabList" :active-tab-key="activeTabKey" @tabChange="(key:string)=>activeTabKey=key">
<template #title v-if="titleVar">
<div class="title">
<div :class="['type', type]" v-if="type"></div>
<component class="icon" :is="icon" v-if="icon"></component>
<span class="text">{{ titleVar }}</span>
</div>
</template>
<template #extra v-if="titleVar">
<DownOutlined class="opt-btn" v-if="reactive && !open" @click="open = true" />
<UpOutlined class="opt-btn" v-if="reactive && open" @click="open = false" />
<unione-btn :widget="btn" v-for="btn in moreBtns" :key="btn.name" :preset="['more']"></unione-btn>
</template>
<template #customTab="tab" v-if="mode == 'tabs'">
<component :is="tab.icon" v-if="tab.icon"></component>
{{ tab.title }}
</template>
<template #tabBarExtraContent>
<unione-btn :widget="btn" v-for="btn in moreTabs" :key="btn.name" :preset="['more']"></unione-btn>
</template>
<template v-if="open">
<UnioneContainer :engine="engine" :wid="widgetObj.wid" v-model:formValue="formValue" v-if="mode === 'normal'">
<slot></slot>
</UnioneContainer>
<UnioneContainer :engine="engine" :wid="activeTabKey" v-model:formValue="formValue" v-if="mode === 'tabs'">
<slot></slot>
</UnioneContainer>
</template>
</a-card>
</Widget>
</template>
核心设计亮点:
– 深度封装 Antd 卡片组件,结合低代码引擎专属 Widget 外层适配
– 区分普通模式、标签页模式双渲染逻辑,一套组件适配两种布局
– 支持折叠展开交互,可自由开启动态伸缩功能,优化页面空间
– 多插槽拆分,标题、拓展按钮、标签样式、内容区完全自定义
2. 逻辑层:引擎深度适配,参数自动化解析
脚本核心适配 Unione 低代码表单引擎,自动读取组件配置、联动表单数据、监听页面变更,完全适配设计器编辑态与运行态。
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import Widget from '../widget.vue'
import utils from '../../lib/utils'
defineOptions({
name: 'UnioneCard'
})
// 属性定义
const props = defineProps({
wid: {
type: String,
required: false
},
engine: {
type: Object,
required: false
},
widget: {
type: Object,
required: false
},
title: {
type: String,
required: false
},
icon: {
type: String,
required: false
},
type: {
type: String,
required: false
},
mode: {
type: String,
default: 'normal' //normal:常规,tabs:卡片
},
reactive: {
type: Boolean,
default: false
},
})
const formValue = defineModel<any>('formValue', {
type: Object,
default: () => { }
})
const open = defineModel({
type: Boolean,
default: true
})
// 组件对象
const widgetObj = computed(() => {
return props.engine?.widget(props.wid) || props.widget || {}
})
const activeTabKey = ref('');
const tabList = computed(() => {
if (props.mode !== 'tabs') {
return []
}
return (widgetObj.value.widgets || []).map((item: any) => ({
…item,
key: item.wid,
}))
})
watch(()=>tabList.value,()=>{
if(tabList.value?.length){
if(!activeTabKey.value){
activeTabKey.value = tabList.value[0].key
}
}else{
activeTabKey.value = ''
}
},{immediate:true})
const titleVar = computed(() => {
return widgetObj.value.title || props.title || ''
})
const moreBtns = computed(() => {
const btns: any = widgetObj.value.props?.moreBtn || []
let mbtn = btns.find((item: any) => item.name === 'more')
const btn: any = {
title: '更多',
name: 'more',
type: 'link',
enable: true
}
if (!mbtn) {
btns.push(btn);
} else {
utils.obj.ext(mbtn, btn);
}
return btns;
})
const moreTabs = computed(() => {
const btns: any = widgetObj.value.props?.moreTabs || []
const mbtn = btns.find((item: any) => item.name === 'more')
const btn: any = {
title: '更多',
name: 'more',
type: 'link',
}
if (!mbtn) {
btns.push(btn);
} else {
utils.obj.ext(mbtn, btn);
}
return btns;
})
</script>
核心逻辑亮点:
1. 双模式智能适配:根据 mode 参数自动切换普通卡片、标签页卡片布局
2. 全自动数据联动:原生绑定表单数据,内部嵌套组件可正常参与表单校验、联动、提交
3. 智能标签激活:自动默认选中首个标签,标签列表变更实时刷新
4. 按钮自适应解析:自动识别、合并、兜底「更多」拓展按钮,无需手动配置
5. 编辑态完美适配:表单设计器拖拽、参数修改实时预览,和原生组件无差异
3. 样式层:精细化视觉分层,企业级UI质感
<style scoped lang="less">
.unione-card {
.title {
font-size: 17px;
display: inline-block;
.icon {
margin-right: 5px;
}
.type {
background-color: #1677ff;
display: inline-block;
width: 12px;
height: 12px;
margin-right: 2px;
&.circle {
border-radius: 6px;
}
&.square {
margin-right: 2px;
}
&.line {
width: 5px;
margin-right: 2px;
}
}
}
.opt-btn {
cursor: pointer;
}
}
</style>
样式优势:内置圆形、方形、线条三种标题标识样式,可自由切换,快速实现页面模块视觉分区,统一系统UI风格,告别杂乱排版。
二、组件接入与使用方式
延续 Unione 低代码极简扩展理念,接入零难度:
1. 保存上述完整组件源码;
2. 在 Vue 项目全局注册 UnioneCard 组件;
3. 刷新表单设计器,即可直接拖拽使用。
接入后可自由配置:卡片标题、图标、标识样式、折叠开关、布局模式、自定义拓展按钮,完全继承平台所有表单联动、权限、打印、多端适配能力。
三、业务落地核心价值
1.页面结构化分层:将零散表单字段按业务模块分区,页面整洁清晰,提升系统专业度;
2.节省页面空间:支持折叠收起冗余模块,适配多字段、长表单场景,告别滚动冗长问题;
3. 多场景全覆盖:基础信息、明细数据、附件资料、操作记录均可独立分卡展示;
4.自定义拓展性强:头部按钮、标签栏、图标样式自由配置,适配个性化UI需求;
5. 轻量化高性能:原生封装、无冗余依赖,渲染流畅,低配服务器也能稳定运行。
四、Docker一键部署,体验完整组件生态
想要体验卡片布局组件、二维码、条形码及全套自定义组件能力,直接本地私有化部署:
git clone https://gitee.com/unione-cloud/unione-docker.git
cd unione-docker
docker-compose up -d
平台访问地址:http://localhost
默认登录账号/密码:admin / admin
开源仓库地址
表单引擎 unione-form-editor
Gitee:https://gitee.com/unione-cloud/unione-form-editor
GitHub:https://github.com/unione-cloud/unione-cloud
流程引擎 unione-flow-editor
Gitee:https://gitee.com/unione-cloud/unione-flow-editor
GitHub:https://github.com/unione-cloud/unione-form-editor
Unione Cloud 平台主仓库
Gitee:https://gitee.com/unione-cloud/unione-cloud
GitHub:https://github.com/unione-cloud/unione-cloud
Docker一键部署脚本仓库
Gitee:https://gitee.com/unione-cloud/unione-docker
最后想说
一套优秀的低代码系统,不仅要看数据录入、流程审批能力,页面布局与视觉体验同样是核心竞争力。
Unione Form Editor 自研 Card 卡片布局组件,补齐了开源低代码布局短板,用极简的拓展方式、丰富的自定义能力,让普通开发者也能快速搭建出整洁、专业、高颜值的企业级业务页面。
后续还会持续更新更多自定义布局、业务组件开发教程,欢迎点赞收藏、持续关注!







