release v1.0.0-rc.11 (#138)
* fix(editor): 页面标题不要换行 * docs: 教程与stageCore * fix(editor): runtime.updateRootConfig可以为空 * fix(editor): 编辑组件是获取parent需要获取到Proxy * fix(editor): 默认page属性值加上layout * fix(stage): magic注入时机应当在iframe onload之后 * chore: release v1.0.0-rc.11 * chore: 更新changlog Co-authored-by: roymondchen <roymondchen@tencent.com>
This commit is contained in:
287
docs/src/tutorial/hello-world.md
Normal file
287
docs/src/tutorial/hello-world.md
Normal file
@@ -0,0 +1,287 @@
|
||||
# 1.Hello World
|
||||
|
||||
## 环境准备
|
||||
|
||||
使用[@vue/cli](https://cli.vuejs.org/zh/guide/installation.html)初始化项目
|
||||
|
||||
```
|
||||
npm install -g @vue/cli
|
||||
```
|
||||
|
||||
> 由于大部分新的webpack插件都已不支持webpack5以下,建议使用@vue/cli@5.0.0及以上版本
|
||||
> 如现有项目是webpack4的,需要注意安装node_module时使用对应的版本
|
||||
> 使用@vue/cli@4的,需要在vue.config.ts 中加入 transpileDependencies: [/@tmagic/]
|
||||
|
||||
::: tip
|
||||
虽然这里使用@vue/cli作为示例教程,但是更推荐使用[vite](https://github.com/vitejs/vite)
|
||||
:::
|
||||
|
||||
::: warning
|
||||
:warning: 如用node 16安装不成功,可以尝试用node 14
|
||||
:::
|
||||
|
||||
## 创建项目
|
||||
|
||||
[关于@vue/cli的详细教程可以查看官方文档](https://cli.vuejs.org/zh/guide/installation.html)
|
||||
|
||||
```
|
||||
vue create hello-world
|
||||
|
||||
cd hello-world
|
||||
```
|
||||
|
||||
得到项目目录如下
|
||||
|
||||
```
|
||||
.
|
||||
└─hello-world
|
||||
└─ public
|
||||
└─ test
|
||||
└─ src
|
||||
├─ APP.vue
|
||||
├─ main.vue
|
||||
└─ components
|
||||
└─ HelloWorld.vue
|
||||
└─ vue.config.js
|
||||
...
|
||||
```
|
||||
|
||||
> src/components在本次教程中暂时没有用到,可以删掉;
|
||||
|
||||
## 添加依赖
|
||||
|
||||
```
|
||||
npm install --save @tmagic/editor @tmagic/form element-plus
|
||||
```
|
||||
|
||||
## 注册组件
|
||||
|
||||
将以下代码覆盖到src/magic.ts中
|
||||
|
||||
```ts
|
||||
import 'element-plus/dist/index.css';
|
||||
import '@tmagic/editor/dist/style.css';
|
||||
import '@tmagic/form/dist/style.css';
|
||||
|
||||
import { createApp } from 'vue';
|
||||
import ElementPlus from 'element-plus';
|
||||
|
||||
import TMagicEditor from '@tmagic/editor';
|
||||
import TMagicForm from '@tmagic/form';
|
||||
|
||||
import App from './App.vue';
|
||||
|
||||
createApp(App)
|
||||
.use(ElementPlus)
|
||||
.use(TMagicEditor)
|
||||
.use(TMagicForm)
|
||||
.mount('#app');
|
||||
|
||||
```
|
||||
|
||||
## 渲染编辑器
|
||||
|
||||
将以下代码覆盖到src/App.vue中
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<m-editor
|
||||
v-model="value"
|
||||
:render="render"
|
||||
:component-group-list="componentGroupList"
|
||||
></m-editor>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
const value = ref();
|
||||
|
||||
const componentGroupList = ref([]);
|
||||
|
||||
const render = () => window.document.createElement('div');
|
||||
</script>
|
||||
|
||||
<style>
|
||||
html,
|
||||
body,
|
||||
#app,
|
||||
.m-editor {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
```
|
||||
|
||||
## 运行项目
|
||||
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
到这里一个空白的编辑器就运行起来了。不出意外,通过浏览器访问http://localhost:8081/,将看到
|
||||
|
||||
<img src="/tutorial/one/init.png" />
|
||||
|
||||
## 添加组件列表
|
||||
|
||||
api详情:[componentGroupList](../api/editor/editor.md#componentGroupList)
|
||||
|
||||
```ts
|
||||
const componentGroupList = ref([
|
||||
{
|
||||
title: '组件列表',
|
||||
items: [
|
||||
{
|
||||
icon: 'https://vfiles.gtimg.cn/vupload/20220614/9cc3091655207317835.png',
|
||||
text: 'HelloWorld',
|
||||
type: 'hello-world',
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
```
|
||||
|
||||
到这里,左侧会出现一个叫HelloWorld的爱心图标,点击它会发现没有反应,代开控制台会发现有error;这是因为还没有创建页面
|
||||
|
||||
点击中间的新增页面也会发现没有反应,这是因为没有编辑器初始值,只需要给value赋上初始值就可以了
|
||||
|
||||
## 设置编辑器初始值
|
||||
|
||||
api详情:[modelValue](../api/editor/editor.md#modelValue)
|
||||
|
||||
```ts
|
||||
const value = ref({
|
||||
type: 'app',
|
||||
items: [],
|
||||
});
|
||||
```
|
||||
|
||||
加上初始值后,点击新增页面就可以渲染出一个画布了,但是点击添加HelloWorld组件依然没有反应
|
||||
|
||||
这是因为这时的编辑器并能理解HelloWorld是什么,需要在[render](../api/editor/editor.html#render)函数中处理
|
||||
|
||||
## 渲染
|
||||
|
||||
api详情:[render](../api/editor/editor.md#render)
|
||||
|
||||
```ts
|
||||
const render = () => {
|
||||
const root = window.document.createElement('div');
|
||||
const page = value.value.items[0];
|
||||
|
||||
if (!page) return root;
|
||||
|
||||
root.id = `${page.value.id}`;
|
||||
|
||||
createApp(
|
||||
{
|
||||
template: '<p v-for="node in config.items" :key="node.id" :id="node.id">hello world</p>',
|
||||
props: ['config'],
|
||||
},
|
||||
{
|
||||
config: page,
|
||||
},
|
||||
).mount(root);
|
||||
|
||||
return root;
|
||||
};
|
||||
```
|
||||
|
||||
这里用到了动态编译Vue模板,所以需要在vue.config.js中添加vue alias
|
||||
|
||||
```js
|
||||
configureWebpack: {
|
||||
resolve: {
|
||||
alias: {
|
||||
vue$: 'vue/dist/vue.esm-bundler.js',
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
> render函数中获取page是通过value.value.items[0],这样只是表示第一个页面,如果页面有多个页面就会有问题
|
||||
> 可以通过[editorService.get('page')](../api/editor/services.md#get)获取到当前选中的页面
|
||||
|
||||
```ts
|
||||
import { editorService } from '@tmagic/editor';
|
||||
import type { MPage } from '@tmagic/schema';
|
||||
|
||||
const page = computed(() => editorService.get<MPage>('page'))
|
||||
```
|
||||
|
||||
到这已经能渲染出HelloWorld组件了,但是会发现无法选中,因为这时并不知道画布中的Dom已经发生变化,所以需要通知编辑器
|
||||
|
||||
需要调用
|
||||
|
||||
```ts
|
||||
renderer.iframe.contentWindow.magic?.onRuntimeReady({});
|
||||
renderer.iframe.contentWindow.magic?.onPageElUpdate(root);
|
||||
```
|
||||
> render函数接收一个stageCore参数 [StageCore](../api/stage/core.md)
|
||||
|
||||
最终完整的render函数实现
|
||||
|
||||
```ts
|
||||
const render = async ({ renderer }: StageCore) => {
|
||||
const root = window.document.createElement('div');
|
||||
|
||||
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.iframe.contentWindow.magic?.onPageElUpdate(root);
|
||||
renderer.iframe.contentWindow.magic?.onRuntimeReady({});
|
||||
});
|
||||
|
||||
return root;
|
||||
};
|
||||
```
|
||||
|
||||
以上就是一个简单的搭建编辑器的示例,安装上面的步骤完成后会发现,可以添加组件,也可选中组件,但是无法拖动,配置属性中的样式也无法生效,这是因为上述的render函数并不完整,没有处理dsl中style,下一节将详细介绍runtime的搭建,将不再使用render函数的方式而是使用[runtimeUrl](../api/editor/editor.md#runtimeurl)。
|
||||
|
||||
::: tip
|
||||
并不是render函数不好,但是从设计上将,render函数还是让渲染逻辑落到了编辑中,@tmagic/editor的设计是希望做到渲染也编辑器解耦
|
||||
:::
|
||||
|
||||
[源码](https://github.com/jia000/tmagic-tutorial)
|
||||
1
docs/src/tutorial/runtime.md
Normal file
1
docs/src/tutorial/runtime.md
Normal file
@@ -0,0 +1 @@
|
||||
# 2.Runtime
|
||||
Reference in New Issue
Block a user