拖拽元素动态函数式使用
约 1158 字大约 4 分钟
...
2026-09-14
前面两节介绍了拖拽元素的功能介绍和基础使用.那么聪明的你,可能已经想到了如何实现动态拖拽元素了吧? 通过后端API获取拖拽元素的 配置信息.以实现数据源的动态拖拽元素.
思路
provider 的本质是一个工厂函数,它接收自定义 options,返回一个带 addElementTypes(context) 的对象:
export default function (options) {
const addElementTypes = function (context) {
context.removePrintElementTypes('testModule'); // 防重复
context.addPrintElementTypes('testModule', [
// key 必须和 providerMap.value 一致
new hiprint.PrintElementTypeGroup('常规', [/* 元素对象数组 */]),
new hiprint.PrintElementTypeGroup('辅助', [/* 元素对象数组 */]),
]);
};
return { addElementTypes };
}后端 JSON Schema参考
1.打印元素类型请关注type和title 它是定义数据来源以及拖拽之前显示的描述。
2.跟业务挂钩的数据表重点关注field和表格的columnFields 它是定义数据来源,数据填充时,根据field来获取数据.
3.每种元素类型的options不好列全,可以在线demo中设计好后,右键->保存为自定义元素 查看。
温馨提示: 后端设计要点
key 建议一个业务模块一个,例如 orderModule、labelModule,避免和内置 defaultModule 冲突。
tid 必须全局唯一,推荐 {key}.{业务名},例如 testModule.text。
schema.js
{
"code": 0,
"msg": "ok",
"data": {
"key": "testModule", // 唯一标识,用于在前端渲染
"groups": [
{
"name": "常规", // 分组名称,根据内容分类展示
"elements": [
{
"tid": "testModule.text",
"type": "text",
"title": "文本",
"options": {
"title": "文本2", // ↓↓↓↓↓↓↓↓ 点击 ↓↓↓↓↓↓↓↓↓
"field": "text",
"testData": "123"
}
},
{
"tid": "testModule.image",
"type": "image",
"title": "图片",
"options": { "width": 100, "height": 100 }
},
{
"tid": "testModule.barcode",
"type": "text",
"title": "barcode",
"options": { "textType": "barcode", "width": 100, "height": 30 }
},
{
"tid": "testModule.qrcode",
"type": "text",
"title": "qrcode",
"options": { "textType": "qrcode", "width": 50, "height": 50 }
},
{
"tid": "testModule.longText",
"type": "longText",
"title": "长文"
},
{
"tid": "testModule.table",
"type": "table",
"title": "表格",
"field": "table",
"columnFields": [
{
"text": "姓名",
"field": "name"
},
{
"text": "性别",
"field": "gender"
},
{
"text": "数量",
"field": "count"
},
{
"text": "金额",
"field": "amount"
}
],
"columns": [
[
{
"title": "姓名",
"align": "left",
"field": "name",
"width": 100
},
{
"title": "性别",
"field": "gender",
"width": 100
},
{
"title": "销售数量",
"field": "count",
"width": 100
},
{
"title": "销售金额",
"field": "amount",
"width": 100
}
]
]
},
{
"tid": "testModule.html",
"type": "html",
"title": "html",
"options": {
"formatter": "function(data, options) {\n return '<div style=\"height:50pt;width:50pt;background:red;border-radius:50%;\"></div>';\n}"
}
},
{
"tid": "testModule.pageBreak",
"type": "text",
"title": "分页符",
"options": {
"hideTitle": true,
"color": "#ff0000",
"textAlign": "center",
"pageBreak": true,
"showInPage": "none"
}
}
]
},
{
"name": "辅助",
"elements": [
{ "tid": "testModule.hline", "title": "横线", "type": "hline" },
{ "tid": "testModule.vline", "title": "竖线", "type": "vline" }
]
}
]
}
}前端 Provider 工厂
函数式的处理,可以加上业务逻辑,例如根据当前用户类型,处理不同的结果。
types/provider.ts
export interface PrintElementSchema {
tid: string;
type: string;
title: string;
options?: Record<string, any>;
[key: string]: any; // 表格的 columns / columnObj 等扩展字段
}
export interface PrintElementGroupSchema {
name: string; // "常规" / "辅助"
elements: PrintElementSchema[];
}
export interface ProviderSchema {
key: string; // "testModule",对应 providerMap.value
groups: PrintElementGroupSchema[];
}utils/providerFactory.ts
import { hiprint } from 'sv-print';
// 或 import { hiprint } from '@sv-print/hiprint';
/**
* 把后端返回的 Schema 转成 <Designer :providers="[...]"> 需要的 provider 函数
* @param schema 后端返回的 { key, groups }
*/
export function createProvider(schema: ProviderSchema) {
const { key, groups } = schema;
const addElementTypes = function (context: any) {
// 1. 先移除旧的,避免热更新 / 重复注册
context.removePrintElementTypes(key);
// 2. 把每个分组转成 PrintElementTypeGroup
const typeGroups = groups.map((g) => new hiprint.PrintElementTypeGroup(g.name, g.elements));
// 3. 注册
context.addPrintElementTypes(key, typeGroups);
};
// 返回真正的 provider 函数(符合 Designer 的 providers 约定)
return function provider(_options?: any) {
return { addElementTypes };
};
}示例代码
demo.vue
<template>
<div style="width: 100vw; height: 100vh">
<!-- 数据没到位就不渲染,避免 addElementTypes 拿到空数组 -->
<Designer v-if="ready" :providers="providers" :providerMap="providerMap" />
<div v-else>加载中...</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { Designer } from '@sv-print/vue3';
import { createProvider } from '@/utils/providerFactory';
import { fetchProviderSchema } from '@/api/print';
const ready = ref(false);
const providers = ref<any[]>([]);
const providerMap = ref({
container: '.hiprintEpContainer', // 左侧元素面板容器
value: '', // 与 provider 的 key 一致
});
onMounted(async () => {
// 1. 拉取后端 Schema
const schema = await fetchProviderSchema('testModule');
if (!schema) {
console.error('后端返回的 schema 为空');
return;
}
// 2. 转成 provider 函数
providers.value = [createProvider(schema)];
// 3. 设置 providerMap
providerMap.value = {
container: '.hiprintEpContainer',
value: schema.key,
};
// 4. 放行渲染
ready.value = true;
});
</script>版权所有
版权归属:sv-print
