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

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

记得点个赞咯~

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

下期再见👋🏻

相关推荐
糕冷小美n2 小时前
elementuivue2表格不覆盖整个表格添加固定属性
前端·javascript·elementui
小哥不太逍遥2 小时前
Technical Report 2024
java·服务器·前端
沐墨染2 小时前
黑词分析与可疑对话挖掘组件的设计与实现
前端·elementui·数据挖掘·数据分析·vue·visual studio code
anOnion3 小时前
构建无障碍组件之Disclosure Pattern
前端·html·交互设计
threerocks3 小时前
前端将死,Agent 永生
前端·人工智能·ai编程
问道飞鱼3 小时前
【前端知识】Vite用法从入门到实战
前端·vite·项目构建
爱上妖精的尾巴4 小时前
8-10 WPS JSA 正则表达式:贪婪匹配
服务器·前端·javascript·正则表达式·wps·jsa
Zhencode4 小时前
Vue3响应式原理之ref篇
vue.js
shadow fish4 小时前
react学习记录(三)
javascript·学习·react.js
小疙瘩5 小时前
element-ui 中 el-upload 多文件一次性上传的实现
javascript·vue.js·ui