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

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

记得点个赞咯~

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

下期再见👋🏻

相关推荐
mldong7 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排8 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60618 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角9 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!9 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰10 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi11 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen12 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马12 小时前
AI源码分析:拆解模型底层实现逻辑
前端
BillKu13 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss