不知从何时开始,IT从业者已经习惯 了*"CV大法"能 "CV"的 就绝不动一动脑子*。虽然我也经常*"CV"*。这究竟是
人性的扭曲、还是道德的沦丧?

前言
回归正题,本期主要分享一下,如何制作sv-print插件。
通过简单的 hook 机制,vue + antd 写一个插件。
干货满满! 先看效果:

如上图,这两个使用的是 antd 的组件。
插件说明:https://ccsimple.github.io/sv-print-docs/plugin/intro.html
源码获取方式 见文末
开干
创建项目就不多说了吧, 根据CLI自行选择处理这里就以 vue3 为例:
lua
pnpm create vite

安装依赖
perl
pnpm i sv-print @sv-print/vue3 ant-design-vue
新增 plugin 目录,创建需要的文件:
index.ts field.vue
结构如下:

处理hook
index.ts 导出 插件对象:
js
import type { PluginOptions, HookOptions } from "sv-print";
export default function (config?: any): PluginOptions {
let configs = {
...{ name: "插件默认值之类的" },
...config,
};
const hook = initHook(configs);
return {
name: "plugin-demo",
description: "vue3,antd-vue 重写字段名参数",
hooks: [hook],
leastHiprintVersion: "0.1.0",
};
}
初始化initHook:
js
const initHook = (configs: any): HookOptions => {
return {
hook: "init", // 关键: hook key
name: "xx",
description: "xx",
priority: 1,
run: (opts) => initRun(opts, configs),
};
};
处理 init hook 核心逻辑:
js
const initRun = (opts: any, configs: any) => {
console.log(opts);
console.log(configs);
const { Config } = opts;
// 这里返回一个 参数对象
const filedOption = fieldOptionFun(configs);
// 注册/重写 参数
Config.registerItems([filedOption()]);
};
参数具体执行, 我们引入 vue 以及 antd 用到的组件
js
import { createApp } from "vue";
import fieldVueApp from "./field.vue";
import { AutoComplete, Modal } from "ant-design-vue";
const fieldOptionFun = (configs: any) => {
const { fieldList = [], dialog = false } = configs;
return function () {
function t() {
this.name = "field";
}
return (
(t.prototype.createTarget = function (t, i, e) {
// t: 元素对象,i: 元素options, e: 元素printElementType
const fileds = t.getFields();
this.isSelect = fileds && fileds.length > 0;
const el = globalThis.$(
`<div class="hiprint-option-item hiprint-option-item-row">
<div class="hiprint-option-item-label">字段名</div>
<div class="hiprint-option-item-field">
<div id="fieldOption">
</div>
</div>
`
);
this.target = el;
// 创建挂载 vue 组件, 传递参数,监听回调
this.vueApp = createApp(fieldVueApp, {
onChange: (value) => {
console.log("onChange", value);
t && t.submitOption();
},
options: fileds || fieldList,
dialog: dialog,
});
this.vueApp.use(Modal);
this.vueApp.use(AutoComplete);
setTimeout(() => {
// 挂载,获得组件实例, 调用内部方法
this.vueAppIns = this.vueApp.mount("#fieldOption");
}, 0);
return this.target;
}),
(t.prototype.getValue = function () {
return this.vueAppIns && this.vueAppIns.getValue();
}),
(t.prototype.setValue = function (t: any) {
setTimeout(() => {
if (this.vueAppIns) {
this.vueAppIns.setValue(t);
}
}, 0);
}),
(t.prototype.destroy = function () {
if (this.vueApp) {
this.vueApp.unmount();
}
this.target.remove();
}),
t
);
};
};
上面重写,自定义参数的 核心的几个方法:
- createTarget 创建参数 DOM
- getValue 获取值
- setValue 设置值
- destroy 销毁参数 DOM
注意如果你不清楚 重写/自定义参数 : 请先查看文章:参数篇
处理vue组件
首先定义传参,因为肯定需要传递参数,回调之类。
js
const props = defineProps({
dialog: { // 是否弹窗
type: Boolean,
default: false,
},
options: { // 字段名列表
type: String,
default: [],
},
onChange: { // 字段名修改回调
type: Function,
default: () => {},
},
});
然后给外部提供 赋值、获取值的方法。 包含回调处理。
js
const onChange = (value: string) => {
if (props.dialog) {
field.value = value;
open.value = false;
}
props.onChange(field.value);
};
const setValue = (value: string) => {
field.value = value;
};
const getValue = () => {
return field.value;
};
defineExpose({ setValue, getValue });
处理 UI 部分
html
<template v-if="props.dialog">
<a-auto-complete
v-model:value="field"
allowClear
style="width: 100%"
placeholder="请输入字段名"
@click="open = true"
/>
<a-modal v-model:open="open" title="请选择字段名" :footer="null">
<div class="btn-group">
<template v-for="(item, idx) in optionsList" :key="idx">
<a-button @click="onChange(item.value)">{{ item.text }}({{ item.value }})</a-button>
</template>
</div>
</a-modal>
</template>
<template v-else>
<a-auto-complete
v-model:value="field"
:options="optionsList"
allowClear
style="width: 100%"
placeholder="请输入字段名"
@change="onChange"
:filter-option="filterOption"
>
<template #option="{ value: val, text }">
<span style="font-weight: bold">{{ text }}({{ val }})</span>
</template></a-auto-complete
>
</template>
到此,咱们简单的一个 init hook 插件就制作完成了。在sv-print init 的时候,就会执行相应的逻辑。
插件支持多个 hook。
总结
插件代码不是很复杂,什么时候 createApp 创建组件,何时去挂载执行 mount 获取 vue 组件实例,需要认真探索。
sv-print 核心参数执行的流程、赋值、取值的逻辑需要理解清楚。
在使用createApp创建组件时,怎么传参,挂载,调用组件方法。
问题并没有你想象的那么难处理,重要的是找对方法。
如果需要源码,公众号回复:plugin-demo
如果看到这里,你还是疑问,想要一对一技术指导,欢迎私信联系我。
记得点个赞咯~
评论区也可交流,想要不简说说什么技术,疑难解答。
下期再见👋🏻
