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

上篇sv-print可视化打印组件不完全指南② 已经了解了 sv-print 组件库参数及插槽 。本期继续带你深入了解 sv-print自定义扩展 vue3、react 使用的组件

前言

sv-print 是一个使用 Svelte 构建的打印设计器组件。它也可以用于其他 UI 库/框架,如 ReactVue原生html

首先我们要清楚 sv-print@sv-print/vue3@sv-print/react 它们之间的关系:

  1. @sv-print/vue 依赖: sv-print 插件, 给 vue2 提供 Designer 组件。

  2. @sv-print/vue3 依赖: sv-print 插件, 给 vue3 提供 Designer 组件。

  3. @sv-print/react 依赖: sv-print 插件, 给 react 提供 Designer 组件。

总结来说: @sv-print/vue3@sv-print/react 只是一个中间件 ,它只是为特定环境提供一个组件。

所以咱们可以不依赖这些,仅依赖sv-print来自定义自己的 Designer 组件

开干

以 vue3 为例:

先安装依赖: pnpm i sv-print

创建个组件文件: designer.vue

html 复制代码
<template>
  <div ref="el" style="height: 100%"></div>
</template>

<script lang="ts">
import { createApp, defineComponent, onMounted, ref, watch, createVNode, h } from "vue";
import * as SVPrint from "sv-print";
  
export default defineComponent({
  name: "designer",
  // 参数我就不多说了,会的人,知道看文档
  // 更会的人 知道去看 依赖 .d.ts 文件
  props: {
    // 可以根据项目情况,自己设定默认值
    autoConnect: {
      type: Boolean,
      default: true,
    },
    config: Object,
    providers: Array,
    providerMap: Object,
    clearProviderContainer: Boolean,
    showPanels: Boolean,
    plugins: Array,
    template: Object,
    designOptions: Object,
    printData: {
      type: Object || Array,
      default: () => {},
    },
    templateKey: {
      type: String,
      default: "default-template",
    },
    title: {
      type: String,
      default: "默认模板",
    },
    authKey: String,
    headerLogoHtml: String,
    headerTitle: String,
    events: Object,
    tags: Array,
    styleOption: Object,
    showOption: Object,
    paperList: Array,
    theme: String,
    themeList: Array,
    miniMapOriginMode: {
      type: Boolean,
      default: false,
    },
    previewOptions: Object,
    onPreviewClick: Function,
    onImageChooseClick: Function,
    onPanelAddClick: Function,
    onFunctionClick: Function,
  },
  emits: ["onDesigned"],
  setup(props, { slots, emit }) {
    // DOM 实例
    const el = ref(null);
    // 设计器
    const designerRef = ref(null);
    
    // 这是关键方法
    const createSlots = () => {
      let temp = {};
      for (const key in slots) {
        let vNode = createVNode(slots[key]);
        let Slot = defineComponent({
          render() {
            return h("div", vNode);
          },
        });
        let slot = createApp(Slot).mount(document.createElement("div"));
        // HTMLCollection not Array
        temp[key] =
          slot.$el.children.length > 1 ? [...slot.$el.children] : slot.$el.firstElementChild;
      }
      // 创建 svelte slot
      return SVPrint.createSlots(temp);
    };
    // 监听参数变化
    watch(
      () => props,
      (newValue) => {
        const copy = { ...newValue };
        for (let k in copy) {
          if (copy[k] === undefined) {
            delete copy[k];
          }
        }
        copy.$$slots = createSlots();
        designerRef.value?.$set(copy);
      },
      { deep: true }
    );
    // 当前el 挂载后,去挂载 sv-print 设计器
    onMounted(() => {
      const designer = new SVPrint.Designer({
        target: el.value!, // 挂载的DOM节点
        props: {
          ...props,
          ...{ $$scope: {}, $$slots: createSlots() },
        },
      });
      // 设计器的回调,再次抛出给 vue 组件
      designer.$on("onDesigned", (e) => {
        emit("onDesigned", e);
      });
      designerRef.value = designer;
    });
    return { el };
  },
});
</script>

这就是 @sv-print/vue3源码

参数我就不多说了,会的人,知道看文档

更会的人知道去看 依赖 .d.ts 文件

扩展动态更新模板

仔细阅读后,你会发现,可以watch 模板参数,实现动态更新模板。会的人不用多说,为什么我还有多说?

因为这是不简说

我...

html 复制代码
<script lang="ts">
// 省略xxx

// 该缓存就缓存咯~
const designerUtils = ref(null); 

// 监听模板json,调用update
watch(
  () => props.template,
  (newValue) => {
    const json = { ...newValue };
    // 你说为什么,注意执行顺序,还可以优化的哟~
    if(designerUtils.value) {
      designerUtils.printTemplate?.update(json);
    }
  },
  { deep: true }
);
// 改造一下
onMounted(() => {
  const designer = new SVPrint.Designer({
    target: el.value!,
    props: {
      ...props,
      ...{ $$scope: {}, $$slots: createSlots() },
    },
  });
  designer.$on("onDesigned", (e) => {
    designerUtils.value = e.detail.designerUtils;
    emit("onDesigned", e);
  });
  designerRef.value = designer;
});
</script>

自定义 Header 组件

哈? 啥 .d.ts

  • 教你,教你,教你怎么看

创建个组件文件: header.vue

html 复制代码
<template>
  <div ref="el" style="height: 100%"></div>
</template>

<script lang="ts">
import { createApp, defineComponent, onMounted, ref, watch, createVNode, h } from "vue";
import * as SVPrint from "sv-print";
  
export default defineComponent({
  name: "designer",
  props: {
    title: {
      type: String,
      default: "sv-print",
    },
    // 省略 xxx
  },
  setup(props, { slots, emit }) {
    const el = ref(null);
    const headerRef = ref(null);
    
    // 这是关键方法
    const createSlots = () => {
      let temp = {};
      for (const key in slots) {
        let vNode = createVNode(slots[key]);
        let Slot = defineComponent({
          render() {
            return h("div", vNode);
          },
        });
        let slot = createApp(Slot).mount(document.createElement("div"));
        // HTMLCollection not Array
        temp[key] =
          slot.$el.children.length > 1 ? [...slot.$el.children] : slot.$el.firstElementChild;
      }
      // 创建 svelte slot
      return SVPrint.createSlots(temp);
    };
    
    onMounted(() => {
      const header = new SVPrint.Header({
        target: el.value!,
        props: {
          ...props,
          ...{ $$scope: {}, $$slots: createSlots() },
        },
      });
      headerRef.value = header;
    });
    return { el };
  }
});
</script>

仔细看,这个扩展就这样搞完了。

总结

至于 react 组件 原理也是一样的。拿到真是 DOM 去创建 对应的组件就好。

本期应该学会去翻阅依赖源码,不要仅仅停留在使用阶段。

去发掘、发现惊喜。

问题并没有你想象的那么难处理,重要的是找对方法。

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

记得点个赞咯~

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

下期再见👋🏻

相关推荐
顾林海12 分钟前
Flutter 图标和按钮组件
android·开发语言·前端·flutter·面试
雯0609~32 分钟前
js:循环查询数组对象中的某一项的值是否为空
开发语言·前端·javascript
bingbingyihao38 分钟前
个人博客系统
前端·javascript·vue.js
尘寰ya39 分钟前
前端面试-HTML5与CSS3
前端·面试·css3·html5
最新信息41 分钟前
PHP与HTML配合搭建网站指南
前端
前端开发张小七1 小时前
每日一练:3统计数组中相等且可以被整除的数对
前端·python
天天扭码1 小时前
一杯咖啡的时间吃透一道算法题——2.两数相加(使用链表)
前端·javascript·算法
Hello.Reader1 小时前
在 Web 中调试 Rust-Generated WebAssembly
前端·rust·wasm
NetX行者1 小时前
详解正则表达式中的?:、?= 、 ?! 、?<=、?<!
开发语言·前端·javascript·正则表达式
流云一号1 小时前
Python实现贪吃蛇三
开发语言·前端·python