sv-print可视化打印组件不完全指南④

不知从何时开始,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

如果看到这里,你还是疑问,想要一对一技术指导,欢迎私信联系我。

记得点个赞咯~

评论区也可交流,想要不简说说什么技术,疑难解答。

下期再见👋🏻

相关推荐
—Qeyser几秒前
用 Deepseek 写的uniapp血型遗传查询工具
前端·javascript·ai·chatgpt·uni-app·deepseek
web_Hsir1 分钟前
Uniapp Vue 实现当前日期到给定日期的倒计时组件开发
vue.js
codingandsleeping2 分钟前
HTTP1.0、1.1、2.0 的区别
前端·网络协议·http
小满blue4 分钟前
uniapp实现目录树效果,异步加载数据
前端·uni-app
喜樂的CC2 小时前
[react]Next.js之自适应布局和高清屏幕适配解决方案
javascript·react.js·postcss
天天扭码2 小时前
零基础 | 入门前端必备技巧——使用 DOM 操作插入 HTML 元素
前端·javascript·dom
咖啡虫2 小时前
css中的3d使用:深入理解 CSS Perspective 与 Transform-Style
前端·css·3d
烛阴2 小时前
手把手教你搭建 Express 日志系统,告别线上事故!
javascript·后端·express
拉不动的猪3 小时前
设计模式之------策略模式
前端·javascript·面试
旭久3 小时前
react+Tesseract.js实现前端拍照获取/选择文件等文字识别OCR
前端·javascript·react.js