windows部署腾讯tmagic-editor02-Runtime

创建editor项目

将上一教程中的hello-world复制过来,改名hello-editor

创建runtime项目

和hello-editor同级

pnpm create vite

在这里插入图片描述
在这里插入图片描述
删除src/components/HelloWorld.vue

按钮需要用的ts types依赖

pnpm add @tmagic/schema @tmagic/stage

在这里插入图片描述

实现runtime

将hello-editor中的render函数实现移植到runtime项目中

<script setup lang="ts">
import {createApp,ref, computed} from 'vue';
import type StageCore from '@tmagic/stage';

const value = ref({
  type: 'app',
  // 必须加上ID,这个id可能是数据库生成的key,也可以是生成的uuid
  id: 1,
  items: [],
});

const render = async ({renderer}:StageCore) => {
  const root = window.document.createElement('div');
  const page = value.value.items[0];
  if (!page.value) return root;

  const {width = 375, height = 1700} = page.value.style || {};

  root.id = `${page.value.id}`;
  root.style.cssText = `
    width: ${width}px;
    height: ${height}px;
  `;

  createApp(
      {
        template: '<div v-for="node in config.items" :key="node.id" :id="node.id">hello world</div>',
        props: ['config'],
      },
      {
        config: page.value,
      },
  ).mount(root);

  renderer.on('onload', () => {
    const style = window.document.createElement('style');
    // 隐藏滚动条,重置默认样式
    style.innerHTML = `
      body {
        overflow: auto;
      }

      html,body {
        height: 100%; margin: 0;padding: 0;
      }

      html::-webkit-scrollbar {
        width: 0 !important;
        display: none;
      }
    `;

    renderer.iframe?.contentDocument?.head.appendChild(style);

    renderer.contentWindow?.magic?.onPageElUpdate(root);
    renderer.contentWindow?.magic?.onRuntimeReady({});
  });

  return root;
};
</script>

<template>
  <div>

  </div>
</template>

<style scoped>
</style>

新建ui-page.vue文件

<template>
  <div v-if="config" :id="config.id" :style="style">
    <div v-for="node in config.items" :key="node.id" :id="node.id">hello world</div>
  </div>
</template>

<script lang="ts" setup>
import { computed } from 'vue';

const props = defineProps<{
  config: any;
}>();

const style = computed(() => {
  const { width = 375, height = 1700 } = props.config.style || {};
  return {
    width: `${width}px`,
    height: `${height}px`,
  };
});
</script>

将以下代码覆盖到src/App.vue中

<template>
  <uiPage :config="page"></uiPage>
</template>

<script lang="ts" setup>
import { ref } from 'vue';

import uiPage from './ui-page.vue';

const page = ref<any>();
</script>

修改vite.config.js
在这里插入图片描述

启动项目
在这里插入图片描述

修改hello-editor

删除render props,添加runtimeUrl,修改样式app.vue

<template>
  <m-editor
      v-model="value"
      :runtime-url="runtimeUrl"
      :component-group-list="componentGroupList"
  ></m-editor>
</template>

<script lang="ts" setup>
import {ref, createApp, computed} from 'vue';
import {editorService} from '@tmagic/editor';

const page = computed(() => editorService.get('page'));

const value = ref({
  type: 'app',
  // 必须加上ID,这个id可能是数据库生成的key,也可以是生成的uuid
  id: 1,
  items: [],
});

const componentGroupList = ref([
  {
    title: '组件列表',
    items: [
      {
        icon: 'https://vfiles.gtimg.cn/vupload/20220614/9cc3091655207317835.png',
        text: 'HelloWorld',
        type: 'hello-world',
      },
    ],
  },
]);

const runtimeUrl = 'http://localhost:8078/';
</script>

<style>
#app {
  overflow: auto;
}

html,body,#app {
  height: 100%; margin: 0;padding: 0;
}

#app::-webkit-scrollbar {
  width: 0 !important;
  display: none;
}
</style>

在这里插入图片描述
启动hello-editor
在这里插入图片描述

跨域问题

修改editor-runtime下的vite.config.js

 server: {
    port: 8078, //指定端口号
    headers:{
      'Access-Control-Allow-Origin': '*',
    }
  },

runtime与editor通信

到这里项目就可以正常访问了,但是会发现添加组件没有反应。

这是因为在runtime中无法直接获取到editor中的dsl,所以需要通过editor注入到window的magic api来交互

如出现在runtime中出现magic为undefined, 可以尝试在App.vue中通过监听message,来准备获取magic注入时机,然后调用magic.onRuntimeReady,示例代码如下

window.addEventListener('message', ({ data }) => {
  if (!data.tmagicRuntimeReady) {
    return;
  }

  window.magic?.onRuntimeReady({
    // ...
  });
});

注意:这里可能会出现editor抛出message的时候,runtime还没有执行到监听message的情况 编辑器只在iframe onload事件中抛出message 如果出现runtime中接收不到message的情况,可以尝试在onMounted的时候调用magic.onRuntimeReady

修改main.js为main.ts

import { createApp } from 'vue'
import type { Magic } from '@tmagic/stage';
import './style.css';
import App from './App.vue';

declare global {
    interface Window {
        magic?: Magic;
    }
}
createApp(App).mount('#app')

新增tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "moduleResolution": "node",
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "useDefineForClassFields": true,
    "sourceMap": true,
    "baseUrl": ".",
    "types": [
      "webpack-env"
    ],
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

src下新增shims-vue.d.ts

/* eslint-disable */
declare module '*.vue' {
    import type { DefineComponent } from 'vue'
    const component: DefineComponent<{}, {}, any>
    export default component
}

修改runtime下的app.vue

<template>
  <uiPage :config="page"></uiPage>
</template>

<script lang="ts" setup>
import type { RemoveData, UpdateData } from '@tmagic/stage';
import type { Id, MApp, MNode } from '@tmagic/schema';
import { ref,reactive } from 'vue';
import uiPage from './ui-page.vue';
const root = ref<MApp>();

const page = ref<any>();

window.magic?.onRuntimeReady({
  /** 当编辑器的dsl对象变化时会调用 */
  updateRootConfig(config: MApp) {
    root.value = config;
  },

  /** 当编辑器的切换页面时会调用 */
  updatePageId(id: Id) {
    page.value = root.value?.items?.find((item) => item.id === id);
  },

  /** 新增组件时调用 */
  add({ config }: UpdateData) {
    const parent = config.type === 'page' ? root.value : page.value;
    parent.items?.push(config);
  },

  /** 更新组件时调用 */
  update({ config }: UpdateData) {
    const index = page.value.items?.findIndex((child: MNode) => child.id === config.id);
    page.value.items.splice(index, 1, reactive(config));
  },

  /** 删除组件时调用 */
  remove({ id }: RemoveData) {
    const index = page.value.items?.findIndex((child: MNode) => child.id === id);
    page.value.items.splice(index, 1);
  },
});
</script>

同步页面dom给编辑器

由于组件渲染在runtime中,对于编辑器来说是个黑盒,并不知道哪个dom节点才是页面(对于dsl的解析渲染可能是千奇百怪的),所以需要将页面的dom节点同步给编辑器
修改runtime下的app.vue

const pageComp = ref<InstanceType<typeof uiPage>>();

watch(page, async () => {
  // page配置变化后,需要等dom更新
  await nextTick();
  window?.magic?.onPageElUpdate(pageComp.value?.$el);
});

以上就是一个简单runtime实现,以及与编辑的交互,这是一个不完善的实现(会发现组件再画布中无法自由拖动,是因为没有完整的解析style),但是其中已经几乎覆盖所有需要关心的内容

当前教程中实现了一个简单的page,tmagic提供了一个比较完善的实现,将在下一节介绍

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/628874.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PCIE协议-2-事务层规范-Transaction Ordering

2.4.1 事务排序规则 表2-40定义了PCI Express事务的排序要求。此表中定义的规则适用于PCI Express上的所有事务类型&#xff0c;包括内存、I/O、配置和消息事务。在单个流量类别&#xff08;Traffic Class&#xff0c;TC&#xff09;内&#xff0c;这些排序规则适用。不同TC标…

5个不同类型的AI问答机器人你都用过吗?

在科技发达的今天&#xff0c;AI问答机器人已经深入我们的日常生活&#xff0c;各式各样的机器人应用在生活的方方面面。本文给大家推荐5个不同类型的AI问答机器人&#xff0c;看看你都用过哪些&#xff0c;或者有没有兴趣尝试一下呢&#xff1f; 1.高效知识库型&#xff1a;He…

论文解读:Matching Feature Sets for Few-Shot Image Classification

文章汇总 动机 将表示分解为独立的组件应该允许捕获图像的几个不同方面&#xff0c;然后可以有效地使用这些方面来表示新类别的图像。 解决办法 从卷积主干连接多尺度特征映射。在网络中以各种尺度嵌入浅层自关注模块(称为“映射器”)。 流程解读 (a)图中右边的灰色小正方…

C++ LeetCode 刷题经验、技巧及踩坑记录【三】

C LeetCode 刷题经验、技巧及踩坑记录【三】 前言vector 计数vector 逆序vector 删除首位元素vector二维数组排序vector二维数组初始化C 不同进制输出C 位运算C lower_bound()C pairC stack 和 queue 前言 记录一些小技巧以及平时不熟悉的知识。 vector 计数 计数 //记录与首…

面 试 题

过滤器和拦截器的区别 都是 Aop 思想的一种体现&#xff0c;用来解决项目中 某一类 问题的两种接口(工具)&#xff0c;都可以对请求做一些增强 出身 过滤器来自 servlet 拦截器来自 spring 使用范围 过滤器 Filter 实现了 iavax.servlet.Filter 接口&#xff0c;也就是说…

【三家飞机制造商】

1.Boeing 波音 F-15战机 B-52轰炸机 阿帕奇攻击直升机 E-3 2 .Lockheed Martin 洛克希德马丁 F35 F22 F16 F117 C130 U2 3 Raytheon 雷神

高效协同,智慧绘制:革新型流程图工具全解析

流程图&#xff0c;作为一种直观展示工作过程和系统运作的工具&#xff0c;在现代办公和项目管理中发挥着不可或缺的作用。 其优势在于能够清晰、直观地呈现复杂的过程和关系&#xff0c;帮助人们快速理解并掌握关键信息。同时&#xff0c;流程图也广泛应用于各种场景&#xf…

NodeJS V8引擎内存和垃圾回收器

关于max_old_space_size max_old_space_size参数用于指定V8引擎的老生代内存的最大大小。通过增加max_old_space_size参数的值&#xff0c;我们可以提供更多的内存给V8引擎&#xff0c;从而提高应用程序的性能和稳定性。 既然提到了老生代&#xff0c;就不得不提下什么是垃圾&…

tensorrtx-yolov5-v6.0部署在windows系统

前言&#xff1a;最近几天一直在搞这个东西&#xff0c;现在跑通了&#xff0c;为了以后自己看和帮助他人&#xff0c;就记录一下。虽然是跑通了但是觉得怪怪的&#xff0c;感觉不是自己想要的效果&#xff0c;另外这个只能检测图片&#xff0c;不能摄像头实时监测(我暂时没找到…

python中cv2,等等如何修改为中文字体显示,这里以人脸表情识别中文标签为例

中文字体显示 首先下载字体包部署字体包代码实现部分 想必大家在使用python过程中都会遇到&#xff0c;想要显示中文的时候&#xff0c;但是py基本上都是英文字体&#xff0c;下面我将给大家提供一个比较好的解决方案&#xff1a; 首先下载字体包 方法&#xff1a; 我使用的是…

SuperBox设计出图的效率提升!新增内门自动开孔和垫高支架图纸输出功能

越来越多的配电箱项目要求带内门&#xff0c;内门不仅可以有效减少外界灰尘、异物进入配电箱内部&#xff0c;保障配电箱正常运行&#xff0c;还能够隔离操作人员意外触摸导电部件&#xff0c;减少触电事故的发生。但是配电箱在配置内门后&#xff0c;会给设计带来更多的要求&a…

Linux虚拟主机cPanel重置密码

我使用的Hostease的Linux虚拟主机产品默认带普通用户权限的cPanel面板&#xff0c;这边自购买后一直未重新设置过cPanel面板的密码&#xff0c;但是了解到要定期重置一下cPanel面板的密码&#xff0c;以确保主机数据安全&#xff0c;因此想要进行重置cPanel面板的密码&#xff…

Leecode热题100---3:无重复字符的最长子串

题目&#xff1a;给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串的长度。 C&#xff1a; 指针法&#xff0c;使用at读取字符串中的值&#xff1b; #include <iostream> #include <string> #include <vector> #include <windows.…

数据结构【顺序表】

文章目录 1.顺序表的概念线性表物理结构逻辑结构 2.顺序表的分类2.1静态顺序表2.2动态顺序表 3.顺序表接口的实现头文件(SQList.h)如下源文件初始化顺序表销毁顺序表插入扩容尾插头插 封装扩容函数删除尾删头删 查找元素在指定位置前插入数据情况一(指定的位置不是首元素)情况二…

淘宝扭蛋机小程序开发:探索未知的惊喜世界

一、引言 在这个充满无限可能的数字时代&#xff0c;每一次点击都可能带来意想不到的惊喜。淘宝扭蛋机小程序&#xff0c;正是为了满足您对惊喜的渴望&#xff0c;将扭蛋的趣味与购物的便捷完美结合&#xff0c;带您进入一个充满未知与乐趣的惊喜世界。 二、产品介绍 淘宝扭…

Redis教程(二):Redis在Linux环境下的安装

Linux环境下安装&#xff1a; 下载地址&#xff1a;Downloads - Redis 安装步骤&#xff1a; 下载得到一个 tar.gz 压缩文件 上传到Linux的/opt/soft目录&#xff0c;使用以下命令解压 tar -zxvf redis-6.2.14.tar.gz Linux安装基本环境gcc&#xff0c;安装命令 yum insta…

Encoder——Decoder工作原理与代码支撑

神经网络算法 &#xff1a;一文搞懂 Encoder-Decoder&#xff08;编码器-解码器&#xff09;_有编码器和解码器的神经网络-CSDN博客这篇文章写的不错&#xff0c;从定性的角度解释了一下&#xff0c;什么是编码器与解码器&#xff0c;我再学习笔记补充的时候&#xff0c;讲一下…

什么是网络端口?为什么会有高危端口?

一、什么是网络端口&#xff1f; 网络技术中的端口默认指的是TCP/IP协议中的服务端口&#xff0c;一共有0-65535个端口&#xff0c;比如我们最常见的端口是80端口默认访问网站的端口就是80&#xff0c;你直接在浏览器打开&#xff0c;会发现浏览器默认把80去掉&#xff0c;就是…

dfs记忆化搜索,动态规划

动态规划概念&#xff1a; 给定一个问题&#xff0c;将其拆成一个个子问题&#xff0c;直到子问题可以直接解决。然后把子问题的答案保存起来&#xff0c;以减少重复计算。再根据子问题的答案反推&#xff0c;得出原问题解。 821 运行时间长的原因&#xff1a; 重复大量计算…

Cadence 16.6 绘制PCB封装时总是卡死的解决方法

Cadence 16.6 绘制PCB封装时总是卡死的解决方法 在用Cadence 16.6 PCB Editor绘制PCB封装时候&#xff0c;绘制一步卡死一步&#xff0c;不知道怎么回事儿&#xff0c;在咨询公司IT后&#xff0c;发现是WIN系统自带输入法的某些热键与PCB Editor有冲突&#xff0c;导致卡死。 …