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

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

前言

sv-print 是一个使用 Svelte 构建的打印设计器组件。它也可以用于其他 UI 库/框架,如 React 、Vue 和 原生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 去创建 对应的组件就好。

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

去发掘、发现惊喜。

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

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

记得点个赞咯~

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

下期再见👋🏻

相关推荐
沙漠之主5 小时前
C++编程教学设计资料:从入门到实战的完整课程方案
java·前端·c++
hasty5 小时前
不上传新包,也能改变用户拿到的版本:npm dist-tag 的 OIDC 权限治理
前端·npm·node.js
Csvn6 小时前
diff 算法(虚拟 DOM Reconciliation)
前端
前端snow7 小时前
ai agent --- 文件存储
前端
Frag0ut7 小时前
Chrome四大版本获取及共存指南:Stable/Beta/Dev/Canary
前端·chrome·浏览器·dev·beta·canary·共存版
IT_陈寒8 小时前
SpringBoot自动配置坑了我一把,原来是这样绕过去的
前端·人工智能·后端
广州华水科技8 小时前
单北斗GNSS变形监测在大坝安全监测中的应用与优势
前端
zeng不错9 小时前
B站 173 个投稿活动看到眼瞎?我写了个扩展,主打一个精准打击
前端
Latchh9 小时前
前端导出的JPEG红字发糊,质量要拉到100才清楚
前端·图像处理·人工智能·计算机视觉
默_笙9 小时前
🚦 请三个 AI 考官给 RAG 打分:量化评估实战(下)
前端·javascript