
不简说
2023/04/02阅读:21主题:自定义主题1
【vue-plugin-hiprint】实战-动态provider
❝哈喽~ 各位码友😄小伙伴们😊在
❞使用此插件
的时候,应该都有这样的需求,那就是动态加载配置的打印元素。所以~~安排
:实战篇-动态provider
本次实战源码链接: https://github.com/CcSimple/vue-plugin-hiprint-start
效果如图:

前言
本篇围绕以下几点进行阐述:
-
provider
对象格式 -
分析 addElementTypes
方法 -
封装 provider
helper工具 本篇重点 -
动态构建 provider
-
动态更新 provider
1.provider对象格式
虽然我在【vue-plugin-hiprint】如何自定义可拖拽元素 provider一文中已经阐述过了,这里还是对各位小伙伴简单说一下,直接看下方代码(注释还算够细可以吧😊):
/**
* 我在 【vue-plugin-hiprint】如何自定义可拖拽元素 provider 一文中, 已经详细介绍了
* 链接: https://mp.weixin.qq.com/s/n9i1j8hhVJvnlfJRPRtWog
* 格式如下:
* @param {Object} options 这是我们实际传入的参数, 一般是一个对象, 里面包含了一些配置信息
* @return {Object} 返回一个对象, 里面包含了 addElementTypes 方法
*/
// eslint-disable-next-line no-unused-vars
const 格式 = function (options) {
// 这里的 options 是一个对象, 是我们在使用时传入的
// 当然你可以自定义有几个参数 如: function (map,options) {}
console.log(options);
// 这里的 context 是一个对象, 是由 hiprint 内部执行时回调回来的.
// 我们可以 log 出来看看
var addElementTypes = function (context) {
console.log(context);
};
return {
addElementTypes: addElementTypes,
};
};
简单来说,就是返回一个包含 addElementTypes
方法的对象。
2.分析addElementTypes方法
其实也就是去 封装实现 addElementTypes
方法,然后返回。方便在构建之前
去 init
初始化。
在封装之前我们肯定需要清楚这个 addElementTypes
方法到底做了些什么吧,我们先来分析
一下默认的provider(defaultElementTypeProvider
);如下图:

如上图,那么就可以有个大致思路,那就是需要:
-
key
(用于区分和构建使用), -
groupName
(就是个分组名称), -
printElements
(实际元素参数对象,与后端协商确定)
我的思路是这样的:
const createProvider = function (key, options) {
const addElementTypes = function (context) {
// 先清空, 避免重复添加. 如果有特殊需求, 可以不清空
context.removePrintElementTypes(key);
// 实际添加 一般分为以下几步:
// 1. 添加一个key (用于创建 "唯一" 的 "tid" ) -- 对象包含数组: {"key",[]}
// 2. 添加一个分组 (就是为了给元素分组, 便于展示) -- 对象包含数组: {"分组名称",[]}
// 3. 添加分组下的元素数组 (实际的元素操作,都在这里进行) -- 数组包含对象 [{元素格式},{元素格式}]
}
}
👌🏻,大致思路
有了,那就撸起袖子编码呗~ 有问题再调整咯,不然还有什么办法呢🤦。
3.封装provider-helper
新建一个 provder-helper.js
文件;根据先前的分析,先撸两个
方法 export
一下咯~:
/**
* 创建一个 provider, 我这里示例,传入两个参数
* @param {*} key 这个 key 是用于创建 "唯一" 的 "tid" 的, 一般是用于区分不同的 provider
* @param {*} options 这个就需要根据实际情况来定义了,根据项目实际情况与后端协商定义
*/
const createProvider = function (key, options) {
const addElementTypes = function (context) {
// todo: 待实际实现的方法
}
return {
addElementTypes: addElementTypes,
};
}
/**
* 创建多个 provider
* @param {*} optionList 参数列表
*/
const createProviderList = function (optionList) {
const providers = optionList.map((item) => {
return createProvider(item.key, item.options);
});
// 当你不清楚的时候, 可以 log 出来看看
return providers;
};
export default { createProvider, createProviderList };
嗯~ 还算清晰😄;现在就需要各位小伙伴自己
挠一挠动一动脑子了,根据打印元素的数据格式
,怎么去实现这个 addElementTypes
方法。
我先打个样:
-
假设 后端
返回的数据如下:
const data = {
key: "NetProvider1",
options: {
groupName: "NetProvider1分组名称",
printElements: [
{
id: "name",
type: "txt", // 这里的 type 是后端返回的, 需要转换成 hiprint 的 type
width: 100,
height: 20,
title: "名称",
field: "name",
testData: "名称1",
// 协商的可选参数, 没有可选参数就返回 {}
options: {
fontSize: 12,
color: "#f00808",
},
},
{
id: "logo",
type: "img",
width: 100,
height: 100,
title: "logo",
field: "logo",
options: {
src: "https://foruda.gitee.com/avatar/1677050350324030848/5400665_ccsimple_1591166830.png!avatar200",
},
},
{
id: "table",
type: "table",
title: "空白表格",
field: "table",
options: {},
},
{
id: "tableCustom",
type: "tableCustom",
title: "默认表格",
field: "table",
options: {},
columns: [
[
// 省略
],
],
},
],
},
};
-
如上数据格式 后端
返回元素类型
(type)与我们实际需要
的不一致
。那么我们就需要去转换
一下了:
/**
* @description 这是一个示例, 如果后端返回的数据,与我们需要的格式不对应, 那么我们可以在这里进行转换
*/
const PRINT_ELEMENT_TYPE_MAP = {
// 比如后端返回元素类型的是 "txt", 但是我们需要的是 "text"
txt: "text",
img: "image",
// 比如后端返回的 "二维码", 但是我们需要的是 "text", 还需要特殊处理
qrcode: "text",
// 比如后端返回的 "条形码", 但是我们需要的是 "text", 也需要特殊处理
barcode: "text",
table: "table",
tableCustom: "table",
hLine: "hline", // 后端返回的它就是不一样,怼他
vLine: "vline",
rect: "rect",
oval: "oval",
};
有了这个假设
,那么就继续撸干代码~
前面分析
到,需要 1、2、3个步骤
,但是呢,这个 1 需要 2步的内容
; 2步 需要 3步的内容
。嗯~ 所以说,倒过来处理呗:
反过来说, 我们就是需要:
-
先创建元素数组
-
再把这个"元素数组"push到 "分组对象"中
-
最后把这个"分组对象"push到 "key的数组"中
👌上代码:
const createProvider = function (key, options) {
const addElementTypes = function (context) {
// 先清空, 避免重复添加. 如果有特殊需求, 可以不清空
context.removePrintElementTypes(key);
// 第 3 步: 创建元素数组
let printElements = options.printElements.map((item) => {
// 提出来, 方便处理 二维码 条形码;
// 如果和后端约定好,那么就更简单了,直接把后端返回的数据,直接赋值给 options
let options = {
title: item.title, // 在 options 中添加 title, 是可以清空的
field: item.field,
testData: item.testData,
...item.options, // 可选参数之类的, 或者参数都在这里面
};
// 有些元素可以不设置宽高的,比如 table
item.width && (options.width = item.width);
item.height && (options.height = item.height);
// 特殊处理 二维码 条形码
if (["qrcode", "barcode"].includes(item.type)) {
options.textType = item.type;
}
// 基础打印元素选项
let printElement = {
tid: `${key}.${item.id}`, // 确保不重复就行
title: item.title, // 这个 title 清空了,还是会有这个默认值
type: PRINT_ELEMENT_TYPE_MAP[item.type], // 转换后端返回的元素类型
options: options,
};
// 特殊处理 表格 (表格参比较多咯~~~)
if (["table", "tableCustom"].includes(item.type)) {
// 根据实际情况 进行处理
if (item.columns) {
printElement.columns = item.columns;
} else {
printElement.columns = [
[
{ align: "center", width: 100 },
{ align: "center", width: 100 },
],
];
}
return printElement;
}
return printElement;
});
// 第 2 步: 创建分组对象
let printElementGroup = new hiprint.PrintElementTypeGroup(options.groupName, printElements);
// 第 1 步: 添加到 key 数组中
context.addPrintElementTypes(key, [printElementGroup]);
};
return {
addElementTypes: addElementTypes,
};
};
就是这样几步
完成了这个封装
;当然如果后续有什么调整
,调整这个工具类
就好了。
动态构建 provider
工具封装好了
,那就上手试一试
;有报错就看报错原因
,如果没有
,那么恭喜你,我看你骨骼惊奇,是个奇才,非常适合这本.... 思路非常清晰~
// 模拟网络请求,2秒后返回数据。
// clear: 是否需要先清空 再构建
const getProvider1 = (clear = true) => {
new Promise((resolve, reject) => {
loading.value = true;
setTimeout(() => {
resolve(netData1);
}, 2000);
}).then((data) => {
buildProvider(data, clear);
});
};
/**
* 构建provider
* 注意: 构建可拖拽元素必须在 hiprint.init() 之后调用
* 调用之前 可以先 console.log($("#provider-container")) 看看是否有该 dom
*/
const buildProvider = (data, clear) => {
// 组装 provider
if (Array.isArray(data)) { // 如果返回的是数组
let providerList = helper.createProviderList(data);
hiprint.init({ providers: providerList });
} else {
let provider = helper.createProvider(data.key, data.options);
hiprint.init({ providers: [provider] });
}
if (clear) {
$("#provider-container").empty(); // 先清空, 避免重复构建
}
if (Array.isArray(data)) { // 数组就循环去构建
data.forEach((item) => hiprint.PrintElementTypeManager.build($("#provider-container"), item.key));
} else {
hiprint.PrintElementTypeManager.build($("#provider-container"), data.key);
}
loading.value = false;
};
❝实际效果,各位小伙伴可在
❞线上demo去体验
。
动态更新 provider
这个其他就是通过hiprint.updateElementType
这个 API 去动态更新已初始化(init)
的provider
。 只是很多小伙伴可能不知道
这个🤦...
-
比如有个需求说,这个新拖拽的元素, 根据当前登录的用户名
来生成。
那么此时,就可以使用这个来动态更新provider
:
/**
* @param String tid (provider中唯一的值)
* @param {Function} 回调这个tid的对象
* @return {Object} 返回修改后的对象
*/
hiprint.updateElementType('defaultModule.text', (type) => {
// 不知道格式的情况,就 log 看看
console.log(type);
type.title = '这是更新后的元素';
return type;
})
就是这个简单😊。
总结
-
整篇下来,可以看到,实际写代码之前 分析
是很重要的; -
当然与 后端配合
的时候,相互协商
也是很有必要
; -
在 不理解对象格式
的时候,一定要去观察分析结构/格式
; -
代码封装
,平时写的时候能想到
的还是封装一下
;
参数篇
到此结束,如有不清楚的知识点,大家一定要学会自己查阅相关资料
。
如果还想熟悉/了解 【vue-plugin-hiprint】
其他相关功能,欢迎各位留言探讨
。
觉得不错就点个赞
再走咯~
作者介绍
