Designer设计器组件
约 3918 字大约 13 分钟
...
2026-06-01
示例代码
designer.vue
<template>
<!-- 宽高自定义 -->
<div style="width: 100vw; height: 100vh">
<Designer :template="template" @onDesigned="onDesigned" />
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { Designer } from '@sv-print/vue3';
// 先安装所需插件: eg: npm i @sv-print/plugin-ele-bwip-js
// 再引入插件
import pluginEleBwip from '@sv-print/plugin-ele-bwip-js';
const plugins = ref([
pluginEleBwip({}), // 插件参数
]);
const template = ref({});
const utils = ref(null); // 设计器工具对象:设计器的一些操作,都可通过它调用
const onDesigned = (e) => {
console.log('onDesigned');
console.log(e);
const { designerUtils } = e.detail;
utils.value = designerUtils; // 设计器工具对象:设计器的一些操作,都可通过它调用
console.log(designerUtils);
console.log(designerUtils.printTemplate); // 模板对象
console.log(designerUtils.printData); // 打印数据
};
</script>组件参数
基础参数
| 参数键名 | 数据类型 | 默认值 | 说明 | 备注 |
|---|---|---|---|---|
| template | object | {} | 模板json数据 | 也可传整个模板对象支持的参数 |
| printData | object | {} | 打印数据(设计时打印预览) | |
| templateKey | string | default-template | 缓存键(设计保存存入localStorage的键) | |
| title | string | 默认模板 | 导出文件默认名称:模板模板.json | |
| designOptions | object | { grid: true, activePanel: true } | 设计参数,显示网格线,默认激活面板参数 | |
| boolean | `` | 是否自动连接打印客户端 | 即将废弃 设计页面可无需考虑 | |
| paperList | string[] | 默认纸张列表 | 可选纸张列表,见下方参数说明 | |
| config | object | 配置参数 | 参数配置 见下方参数说明 | |
| plugins | object[] | 插件 | 插件机制,扩展参数,扩展打印元素 见下方参数说明 | |
| authKey | string | `` | 授权key | 没有则有体验版水印 |
参数说明:
paperList
// vue3 为例
const paperList = ref([
{ type: 'A1', width: 594, height: 841 },
{ type: 'A2', width: 420, height: 594 },
{ type: 'A3', width: 297, height: 420 },
{ type: 'A4', width: 210, height: 297 },
{ type: 'A5', width: 148, height: 210 },
{ type: 'A6', width: 105, height: 148 },
{ type: 'A7', width: 74, height: 105 },
{ type: 'B1', width: 728, height: 1030 },
{ type: 'B2', width: 515, height: 728 },
{ type: 'B3', width: 364, height: 515 },
{ type: 'B4', width: 257, height: 364 },
{ type: 'B5', width: 182, height: 257 },
{ type: 'B6', width: 91, height: 182 },
{ type: 'B7', width: 64, height: 91 },
]);config
// vue3 为例
<template>
<!-- 宽高自定义 -->
<div style="width: 100vw; height: 100vh">
<Designer :config="config"></Designer>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { hiprint } from '@sv-print/vue3';
// 同 setConfig API
const config = ref({
// 部分参数 需要在 渲染 之前执行. 否则会失效.
showAdsorbLine: true, // 是否显示吸附线
showPosition: true, // 是否显示元素位置
showSizeBox: true, // 是否显示元素大小框
});
// 如下代码
hiprint.setConfig({
// 部分参数 需要在 渲染 之前执行. 否则会失效.
showAdsorbLine: true, // 是否显示吸附线
showPosition: true, // 是否显示元素位置
showSizeBox: true, // 是否显示元素大小框
});
</script>designOptions
// vue3 为例
<template>
<!-- 宽高自定义 -->
<div style="width: 100vw; height: 100vh">
<Designer :designOptions="designOptions"></Designer>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
const designOptions = ref({
grid: true, // 显示网格线
activePanel: true, // 默认显示面板参数
adaptToSize: true, // 纸张缩放适应屏幕大小
});
</script>plugins 设计器注册
// vue3 为例
<template>
<!-- 宽高自定义 -->
<div style="width: 100vw; height: 100vh">
<Designer :plugins="plugins"></Designer>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { Designer } from '@sv-print/vue3';
// 先安装所需插件: eg: npm i @sv-print/plugin-ele-bwip-js
// 再引入插件
import pluginEleBwip from '@sv-print/plugin-ele-bwip-js';
const plugins = ref([
pluginEleBwip({}), // 插件参数
]);
</script>plugins插件注册
import { hiprint } from 'sv-print';
import pluginEleBwip from '@sv-print/plugin-ele-bwip-js';
hiprint.register({
authKey: '', // 授权key, 没有则有体验版水印
plugins: [
pluginEleBwip({}), // 插件参数
],
});构建可拖拽元素相关
| 参数键名 | 数据类型 | 默认值 | 说明 | 备注 |
|---|---|---|---|---|
| providerJson | object[] | undefined | 可拖拽元素json数组 | |
| providerRender | Function | undefined | 可拖拽元素渲染器 | |
| providers | object[] | [] | 可拖拽元素 provider | |
| providerMap | object|object[] | { container: ".hiprintEpContainer", value: "defaultModule" } | 构建可拖拽元素的容器,provider的键 | |
| clearProviderContainer | boolean | true | 构建provider时 是否先清空容器 | |
| tags | string[] | [".draggable-ele"] | 可拖拽元素 选择器 |
参数说明:
providerJson
<template>
<!-- 宽高自定义 -->
<div style="width: 100vw; height: 100vh">
<Designer :providerJson="providerJson" :providerRender="providerRender" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const providerJson = ref([
{
name: 'defaultModule',
list: [
{
name: '测试',
printElementTypes: [
{
title: '横线1',
tid: 'defaultModule.hline1',
type: 'hline',
},
],
},
],
},
]);
const providerRender = ref((list) => {
let container = globalThis.$('<div class="hiprint-printElement-type"></div>');
list.forEach(function (item) {
const box = globalThis.$(`
<div class="draggable-ele-group">
<span class="title">${item.name}</span>
<div class="list"></div>
</div>
`);
const typeList = box.find('.list');
item.printElementTypes.forEach(function (t) {
typeList.append(`
<div class="draggable-ele ep-draggable-item" tid=${t.tid}>
<i class="svicon sv-base sv-${t.type}"></i>
<p style="white-space:nowrap">${t.getText()}</p>
</div>
`);
});
container.append(box);
});
return container;
});
</script>provider.js
import { hiprint } from 'sv-print';
export default function (options) {
var addElementTypes = function (context) {
context.removePrintElementTypes('ibujianModule'); // 避免重复添加
context.addPrintElementTypes('ibujianModule', [
new hiprint.PrintElementTypeGroup('i不简', [
{
tid: 'ibujianModule.text', // 唯一 key
type: 'text', // 元素类型
title: '文本', // 这里和 options 中的 title 一样。"拖拽时就显示" 优先级高于 options 的, "无法彻底删除"
options: {
// 参数同 模板json数据格式 中的 options, 可以不用指定 left, top
title: '文本2', // 标题
field: 'text', // 字段名
testData: '123', // 测试数据
},
},
]),
]);
};
return {
addElementTypes: addElementTypes,
};
}providers参数
// vue3 为例
import provider from './provider.js';
// 注意留意, addPrintElementTypes("ibujianModule", []) 中的 "ibujianModule"
const providers = ref([provider]);providerMap参数
// vue3 为例
// 默认值, 指定 ".hiprintEpContainer" 容器, 构建 "defaultModule" 的 provider
const providerMap = ref({
container: '.hiprintEpContainer',
value: 'defaultModule',
// 可选,自定义渲染的 UI
render: (list) => {
let container = globalThis.$('<div class="hiprint-printElement-type"></div>');
list.forEach(function (item) {
const box = globalThis.$(`
<div class="draggable-ele-group">
<span class="title">${item.name}</span>
<div class="list"></div>
</div>
`);
const typeList = box.find('.list');
item.printElementTypes.forEach(function (t) {
typeList.append(`
<div class="draggable-ele ep-draggable-item" tid=${t.tid}>
<i class="svicon sv-base sv-${t.type}"></i>
<p style="white-space:nowrap">${t.getText()}</p>
</div>
`);
});
container.append(box);
});
return container;
},
});
// 构建前先清空容器
const clearProviderContainer = ref(true);
// 也可以指定多个容器, 构建多个 provider
const providerMapList = ref([
{
container: '.hiprintEpContainer',
value: 'defaultModule',
},
{
container: '.hiprintEpContainer2',
value: 'defaultModule2',
},
]);tags参数
// vue3 为例
<template>
<!-- 宽高自定义 -->
<div style="width: 100vw; height: 100vh">
<Designer :tags="tags">
<template #other>
<div class="draggable-ele" tid="defaultModule.text">这个元素可拖拽</div>
<div class="ibujian" tid="defaultModule.text">这个元素可拖拽</div>
<div class="xxxx" tid="defaultModule.text">不可以,不可拖拽</div>
</template>
</Designer>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { Designer } from '@sv-print/vue3';
const tags = ref(['.draggable-ele', '.ibujian']);
</script>设计器函数重写
| 参数键名 | 数据类型 | 默认值 | 说明 | 备注 |
|---|---|---|---|---|
| events | object | {} | 保存,编辑模板,编辑打印数据,快捷键 | |
| onPreviewClick | function(e: MouseEvent):boolean | 预览 点击事件 | 返回 "true|false" 是否阻止冒泡 | |
| onImageChooseClick | function(target: any) | 图片选择点击事件 | ||
| onPanelAddClick | function(panel, createPanel) | 多面板点击 "+" 事件 | ||
| onFunctionClick | function( option, printElement, event) | 函数/textarea点击事件 | ||
| onZoomChange | function(scale) | 缩放回调 | ||
| customDataFun | function( ele, data, field, printData) | 自定义获取字段数据 返回数据 | ||
| onBeforeDragIn | function( printTemplate, panel, printElement) | 元素拖入之前的回调 | 返回 false 阻止拖入 |
参数说明:
events事件
// vue3 为例
<template>
<!-- 宽高自定义 -->
<div style="width: 100vw; height: 100vh">
<Designer :events="events"></Designer>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { Designer } from '@sv-print/vue3';
const events = ref({
// 保存模板
onSave: (key: string, data: unknown) => {
console.log('保存模板');
return true; // 返回 true 阻止冒泡
},
// 编辑模板
onEdit: (data: unknown) => {
console.log('编辑模板');
return true; // 返回 true 阻止冒泡
},
// 编辑打印数据
onEditData: (data: unknown) => {
console.log('编辑打印数据');
return true; // 返回 true 阻止冒泡
},
// 快捷键
onKeyDownEvent: (e: KeyboardEvent, designerUtils: unknown) => {
console.log('快捷键');
return true; // 返回 true 阻止冒泡
},
});
</script>onPreviewClick事件
// vue3 为例
<template>
<!-- 宽高自定义 -->
<div style="width: 100vw; height: 100vh">
<Designer :onPreviewClick="onPreviewClick" @onDesigned="onDesigned"></Designer>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
const designerUtils = ref();
const onDesigned = (e) => {
console.log('注意看 onDesigned 回调参数: ');
console.log(e);
const { designerUtils: aa } = e.detail;
designerUtils.value = aa;
};
const onPreviewClick = (e: MouseEvent) => {
console.log('预览点击事件');
console.log(e);
const designFields = designerUtils.value.printTemplate.getFieldsInPanel();
console.log(designFields);
const testData = designerUtils.value.printTemplate.getTestData();
console.log(testData);
designerUtils.value.printData = { ...testData, ...printData };
// true: 阻止冒泡
// false: 继续冒泡-> 继续执行默认行为
return false;
};
</script>onImageChooseClick事件
// vue3 为例
<template>
<!-- 宽高自定义 -->
<div style="width: 100vw; height: 100vh">
<Designer :onImageChooseClick="onImageChooseClick"></Designer>
</div>
</template>
<script setup lang="ts">
const onImageChooseClick = (target: unknown) => {
console.log('图片 选择点击事件');
console.log(target);
target.refresh('https://sv-print.ibujian.cn/logo.png');
};
</script>onPanelAddClick事件
// vue3 为例
<template>
<!-- 宽高自定义 -->
<div style="width: 100vw; height: 100vh">
<Designer :onPanelAddClick="onPanelAddClick"></Designer>
</div>
</template>
<script setup lang="ts">
const onPanelAddClick = (panel, createPanel) => {
console.log('多面板 新增 点击事件');
console.log(panel);
panel.name = '新面板' + (panel.index + 1);
createPanel(panel);
};
</script>customDataFun回调
// vue3 为例
<template>
<!-- 宽高自定义 -->
<div style="width: 100vw; height: 100vh">
<Designer :customDataFun="fun"></Designer>
</div>
</template>
<script setup lang="ts">
// 第4个参数 printData, 兼容表格列数据获取.
const customDataFun = (ele, data, field, printData) => {
// ele 是当前元素/表格列
let fieldData;
const fieldList = `${field}`.split(',');
const len = fieldList.length;
for (var i = 0; i < len; i++) {
const f = fieldList[i];
const curData = f.split('.').reduce((a, c) => (a ? a[c] : data ? data[c] : ''), false) || '';
// 如果是表格: curData 是个对象哟
if (typeof curData == 'object') {
if (Array.isArray(curData)) {
fieldData = [...(fieldData || []), ...curData];
} else {
fieldData = { ...(fieldData || {}), ...curData };
}
} else {
const connector = i == 0 ? '' : '->';
// 有必要考虑 number 情况么?
fieldData = `${fieldData || ''}${connector}${curData}`;
}
}
return fieldData;
};
const fun = ref(customDataFun);
</script>onBeforeDragIn事件
// vue3 为例
<template>
<!-- 宽高自定义 -->
<div style="width: 100vw; height: 100vh">
<Designer :onBeforeDragIn="onBeforeDragIn"></Designer>
</div>
</template>
<script setup lang="ts">
const onBeforeDragIn = ref((printTemplate, panel, ele) => {
ele.options.title += '+beforeDragIn';
if (ele.printElementType.type == 'image') {
// 返回 false 阻止拖入
return false;
}
});
</script>设计器回调
回调中的 designerUtils 是核心的工具类, 提供了设计器的所有功能. 比如:导入,导出,打印数据,预览,弹窗等等。
| 参数键名 | 数据类型 | 默认值 | 说明 | 备注 |
|---|---|---|---|---|
| onDesigned | function | 组件初始化完成回调 | 见参数说明 |
下一节 查看更多 designerUtils 的方法
参数说明:
回调示例
// vue3 为例
<template>
<!-- 宽高自定义 -->
<div style="width: 100vw; height: 100vh">
<Designer @onDesigned="onDesigned"></Designer>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { Designer } from '@sv-print/vue3';
const utils = ref();
const onDesigned = (e) => {
console.log('注意看 onDesigned 回调参数: ');
console.log(e);
const { hiprint, designerUtils } = e.detail;
console.log(hiprint);
// 核心工具类, 单例对象
utils.value = designerUtils;
console.log(designerUtils);
// 设计器的 模板对象
console.log(designerUtils.printTemplate);
// 示例: 更新模板json数据
designerUtils.printTemplate.update({});
// 示例: 更新打印数据 (仅用于设计器内预览时的数据)
designerUtils.printData = { name: '不简说' };
// 示例: 导出模板json文件
designerUtils.export();
};
</script>UI样式参数
| 参数键名 | 数据类型 | 默认值 | 说明 | 备注 |
|---|---|---|---|---|
| theme | string,object | light | 默认主题,支持自定义主题 | |
| themeList | string[] | 支持的所有主题 | 可选主题列表,见下方参数说明 | |
| showPanels | boolean | true | 是显示多面板操作区域 | |
| headerLogoHtml | string | <i class="svp-header-logo svicon sv-print"></i> | 默认 Header 左侧logo样式 | |
| headerTitle | string | sv-print | 默认 Header title | |
| headerNewEle | string | false | 默认 Header 是否新建元素 | true则清空默认元素,以 headerEleList 为准 |
| headerEleList | string | [] | 默认 Header 元素列表 | |
| headerNewMenu | string | false | 默认 Header 是否新建菜单 | true则清空默认菜单,以 headerMenuList 为准 |
| headerMenuList | string | [] | 默认 Header 菜单列表 | |
| miniMapOriginMode | boolean | false | 概览图原始模式 | |
| previewOptions | object | {} | 预览参数 | |
| styleOption | object | {} | 默认小组件样式,位置 | |
| rulerStyle | object | {} | 标尺样式 | |
| showOption | object | {} | Header,Toolbar,Footer显示控制 |
参数说明:
自定义主题
// 颜色参考 https://daisyui.com/docs/colors/
export type themeType = {
theme?: string; // 主题名称
primaryColor: string; // 主题色
primaryContent?: string; // 主题色内容颜色
secondaryColor?: string; // 次级主题色
secondaryContent?: string; // 次级主题色内容颜色
accentColor?: string; // 强调色
accentContent?: string; // 强调色内容颜色
neutralColor?: string; // 中性色
neutralContent?: string; // 中性色内容颜色
base100?: string; // 基础色
base200?: string; // 基础色
base300?: string; // 基础色
baseContent?: string; // 基础色内容颜色
info?: string; // 信息色
infoContent?: string; // 信息色内容颜色
success?: string; // 成功色
successContent?: string; // 成功色内容颜色
warning?: string; // 警告色
warningContent?: string; // 警告色内容颜色
error?: string; // 错误色
errorContent?: string; // 错误色内容颜色
};themeList
// vue3 为例
const themeList = ref([
'light',
'dark',
'cupcake',
'bumblebee',
'emerald',
'corporate',
'synthwave',
'retro',
'cyberpunk',
'valentine',
'halloween',
'garden',
'forest',
'aqua',
'lofi',
'pastel',
'fantasy',
'wireframe',
'black',
'luxury',
'dracula',
'cmyk',
'autumn',
'business',
'acid',
'lemonade',
'night',
'coffee',
'winter',
]);Header相关参数
<template>
<!-- 宽高自定义 -->
<div style="width: 100vw; height: 100vh">
<Designer
headerLogoHtml="<i class='svp-header-logo svicon sv-print'></i>"
headerTitle="sv-print"
:headerNewEle="headerNewEle"
:headerEleList="headerEleList"
:headerNewMenu="headerNewMenu"
:headerMenuList="headerMenuList"
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { Designer } from '@sv-print/vue3';
const headerNewEle = ref(false); // 是否重新 创建元素
const headerEleList = ref([
{
gap: true,
},
{
icon: 'sv-base',
title: '基础',
children: [
{
type: 'defaultModule.hline', // provider tid
icon: 'sv-hline',
title: '横线',
},
],
},
]);
const headerNewMenu = ref(false); // 是否重新 创建菜单
const headerMenuList = ref([
{
icon: 'sv-new',
title: '新建',
click: (util) => util.newTemplate(),
},
{
icon: 'sv-templates',
title: '本地模板',
click: (util) => util.openTemplateList(),
},
{
icon: 'sv-save',
title: '保存',
children: [
{
icon: 'sv-browser',
title: '保存到浏览器',
desc: 'Ctrl / Command + S',
click: (util) => util.save(),
},
{
icon: 'sv-edit',
title: '编辑模板数据',
desc: 'Ctrl / Command + E',
click: (util) => util.edit(),
},
{
icon: 'sv-edit-data',
title: '编辑打印数据',
desc: 'Ctrl / Command + D',
click: (util) => util.editData(),
},
{
icon: 'sv-element',
title: '编辑拖拽元素',
desc: 'Ctrl / Command + J',
click: (util) => util.editPrintElementJson(),
},
{
icon: 'sv-export',
title: '导出到本地文件',
desc: 'Ctrl / Command + Shift + S',
click: (util) => util.export(),
},
{
icon: 'sv-import',
title: '从本地文件导入',
desc: 'Ctrl / Command + O',
click: (util) => util.import(),
},
],
},
{
icon: 'sv-preview',
title: '预览',
click: (util, e) => util.previewClick(e),
},
]);
</script>previewOptions
// vue3 为例
const previewOptions = ref({
showPdf: true, // 是否显示 导出pdf按钮
showImg: true, // 是否显示 导出图片按钮
showPrint2: true, // 是否显示 直接打印&打印机列表
});styleOption
// vue3 为例
const styleOption = ref({
panels: {
// 多面板
mode: 'left',
style: 'left:calc(28%);top:100px;',
},
draggableEls: {
// 可拖拽元素
mode: 'default', // 拖拽模式: default(默认), top(上), bottom(下), left(左), right(右), fixed(固定)
show: true, // 是否显示 默认: true
html: '<i class="svicon sv-element"></i><span>拖拽元素</span>', // 缩放 左侧的 按钮/icon (一般不用)
style: 'left:20px;top:95px;width:200px;height:calc(100% - 340px);', // 样式
showOtherIcon: true, // 比如新版本 是否显示 编辑拖拽元素 按钮
otherIconRender: (target) => {
// 自行插入
console.log(target);
},
},
options: {
mode: 'default',
html: '<i class="svicon sv-options"></i><span>属性</span>',
style: 'right:0;top:95px;width:270px;height:calc(100% - 130px);',
},
pageStructure: {
mode: 'default',
html: '<i class="svicon sv-structure"></i><span>页面结构</span>',
style: 'right:280px;top:95px;width:200px;height:calc(100% - 130px - 200px);',
},
history: {
mode: 'default',
html: '<i class="svicon sv-history"></i><span>历史记录</span>',
style: 'right:280px;bottom:30px;width:200px;height:200px;',
},
locationExchange: {
mode: 'default',
show: false,
html: '<i class="svicon sv-switch"></i><span>位置交换</span>',
style: 'right:490px;top:95px;width:300px;height:400px',
},
miniMap: {
mode: 'default',
html: '<i class="svicon sv-flow"></i><span>概览图</span>',
style: 'left:28px;bottom:30px;width:240px;height:200px',
},
editableTools: {
mode: 'top',
style: 'left:280px;top:180px;',
},
zIndexTools: {
mode: 'top',
style: 'left:280px;top:300px;',
},
fontTools: {
mode: 'top',
style: 'left:280px;top:420px;',
},
zoomTools: {
mode: 'left',
style: 'left:240px;top:100px;',
},
rotateTools: {
mode: 'bottom',
style: 'left:440px;top:180px;',
},
});rulerStyle
const rulerStyle = ref({
show: true, // 是否显示 标尺
// 标尺
size: 24, // // 标尺宽度 X:高 Y:宽
backgroundColor: '#fff', // 背景色
fontSize: 12, // 字体大小
fontColor: '#1f1f1f', // 字体颜色
fontWeight: '', // 字体粗细
fontMode: 'right', // 文本展示位置 "center" | "right";
// 刻度
gap: 3.78, // 刻度间距
tickColor: '#1f1f1f', // 刻度颜色
tickWidth: 1, // 刻度宽度
// 单位
unitMode: 'mm', // pt | mm
unit: {
backgroundColor: '#fff', //// 背景色
fontColor: '#343a40', // 字体颜色
fontSize: 10, // 字体大小
},
// border
border: true, // 是否显示 边框
borderColor: '#1f1f1f', // 边框颜色
borderWidth: 1, // 边框宽度
// 显示元素矩形大小
paperRect: true,
paperRectColor: '#f5f5f5',
});showOption
// vue3 为例
const showOption = ref({
showHeader: true, // 是否显示 顶部 Header
showToolbar: true, // 是否显示 工具栏 Toolbar
showFooter: true, // 是否显示 底部 Footer
// 即将废弃移除
showPower: true, // 是否显示 "powered by sv-print" 需要 authKey 支持
});组件插槽
插槽一览
| 插槽名称 | 描述 |
|---|---|
| header | 设计器顶部 Header |
| toolbar | 设计器顶部 工具栏 |
| draggableEls | 设计器左侧 拖拽元素 |
| other | 设计器 其他位置 |
插槽插图

版权所有
版权归属:sv-print
