首页 > 其他分享 >简单的低开编辑器(一):实现组件渲染

简单的低开编辑器(一):实现组件渲染

时间:2023-11-19 22:56:53浏览次数:36  
标签:const 低开 data component 编辑器 editor props 组件 config

好家伙,

 

项目目录如下: 该项目使用Vue3, Element-plus

 

效果图如下:

 

 开搞:

1.写出简单界面

App.vue
<template>
  <div class="app">
    <Editor v-model="state"></Editor>
  </div>
</template>
  
<script>
import { ref, provide } from 'vue';
import data from './data.json'
import Editor from './packages/editor'
import { registerConfig as config } from './utils/editor-config'
export default {
  components: {
    Editor
  },
  setup() {
    const state = ref(data);
    console.log(config)
    provide('config', config);

    return {
      state
    }
  }

}
</script>
  
<style lang="scss">
.app {
  position: fixed;
  top: 20px;
  left: 20px;
  right: 20px;
  bottom: 20px;
}
</style>

 

editor.jsx

import { computed, defineComponent,inject } from "vue";
import './editor.scss'
import EditorBlock from "./editor-block";
export default defineComponent({
    props: {
        modelValue: { type: Object }
    },
    setup(props) {
        const data = computed({
            get() {
                return props.modelValue
            }
        })
        console.log(data.value)

        const containerStyles = computed(() => ({
            width: data.value.container.width + 'px',
            height: data.value.container.height + 'px'
        }))

        const config= inject('config')

        return () => <div>
            <div class="editor-left">
                {/* 根据注册列表 渲染对应的内容 */}
                {config.componentList.map(component=>(
                    <div class="editor-left-item">
                        <span>{component.label}</span>
                        <div>{component.preview()}</div>

                    </div>
                ))}
            </div>

            <div class="editor-top">菜单栏</div>
            <div class="editor-right">属性控制栏目</div>
            <div class="editor-container">
                <div class="editor-container-canvas">
                    {/* 产生内容 */}
                    <div class="editor-container-canvas__content" style={containerStyles.value}>
                        {
                            (data.value.blocks.map(block=>(
                                <EditorBlock block={block}></EditorBlock>
                            )))
                        }
                    </div>
                </div>
            </div>

        </div>
    }
})

editor.scss

.editor {
    width: 100%;
    height: 100%;

    &-left,
    &-right {
        position: absolute;
        width: 270px;
        background: red;
        top: 0;
        bottom: 0;
    }

    &-left {
        left: 0;
        &-item{
            width:200px;
            margin:20px auto;
            display: flex;
            justify-content:center;
            align-items: center;
            background: #fff;
            padding:20px;
            cursor:move;
            user-select: none;
            min-height: 80px;
            position: relative;
            > span{
                position: absolute;
                top:0;
                left:0;
                background: rgb(96, 205, 224);
                color:#fff;
                padding:4px;
            }
            &::after{
                content: '';
                position: absolute;
                top:0;
                left:0;
                right:0;
                bottom:0;
                background: #ccc;
                opacity:0.2 ;
            }
        }
    }

    &-right {
        right: 0
    }

    &-top {
        position: absolute;
        right: 280px;
        left: 280px;
        height: 80px;
        background: blue;
    }

    &-container {
        padding: 80px 270px 0;
        height: 100%;
        box-sizing: border-box;

        &-canvas {
            overflow: scroll;
            height: 100%;

            &__content {
                margin: 20px auto;
                width: 9999px;
                height: 10000px;
                background: yellow;
                position: relative;
            }
        }
    }
}

.editor-block{
    position: absolute;
}

 

 

2.构造假数据 实现根据位置渲染内容

我们随便写一些假数据

data.json

{
    "container":{
        "width":"550",
        "height":"550"

    },
    "blocks":[
        {"top":100,"left":100,"zIndex":1,"key":"text"},
        {"top":200,"left":200,"zIndex":1,"key":"button"},
        {"top":300,"left":300,"zIndex":1,"key":"input"}
    ]
}

现在我要实现的效果是,

我的容器大小能够变为以上data.json中"container"的大小,并能够将"blocks"中的三个组件渲染到容器中

 

创建工具类,为组件进行注册

editor-config.jsx

//列表去可以显示所有的物料
//key对应的组件映射关系
import {ElButton,ElInput} from 'element-plus'

function createEditorConfig(){
    const componentList =[];
    const componentMap ={}

    return{
        componentList,
        componentMap,
        register:(component)=>{
            componentList.push(component);
            componentMap[component.key] = component
        }
    }
}
export let registerConfig = createEditorConfig(); 
registerConfig.register({
    label:'文本',
    preview:()=>'预览文本',
    render:()=>'渲染文本',
    key:'text'
});
registerConfig.register({
    label:'按钮',
    preview:()=><ElButton>预览按钮</ElButton>,
    render:()=><ElButton>渲染按钮</ElButton>,
    key:'button'
});
registerConfig.register({
    label:'输入框',
    preview:()=><ElInput placeholder='预览输入框'>预览按钮</ElInput>,
    render:()=><ElInput placeholder='渲染输入框'>预览按钮</ElInput>,
    key:'input'
});
console.log(registerConfig)

 此处preview属性用于预览组件,render属性用于渲染组件

 

在App.vue中数据传输

<Editor v-model="state"></Editor>
/.
 .
 .
 ./
import data from './data.json'
import { registerConfig as config } from './utils/editor-config'
export default {
  components: {
    Editor
  },
  setup() {
    const state = ref(data);
    console.log(config)
    provide('config', config);

    return {
      state
    }
  }
}

 

 

再次来到editor.jsx中



 props: {
        modelValue: { type: Object }
    },

setup(props) {
        const data = computed({
            get() {
                return props.modelValue
            }
        })
        console.log(data.value)

        const containerStyles = computed(() => ({
            width: data.value.container.width + 'px',
            height: data.value.container.height + 'px'
        }))
<div class="editor-container-canvas__content" style={containerStyles.value}>

通过样式绑定,完成从.json到样式的修改

 

 

3.渲染组件列表

配置组件对应的映射关系 {preview:xxx,render:xxx}后 在editor.jsx中
const config= inject('config')
return () => <div>
            <div class="editor-left">
                {/* 根据注册列表 渲染对应的内容 */}
                {config.componentList.map(component=>(
                    <div class="editor-left-item">
                        <span>{component.label}</span>
                        <div>{component.preview()}</div>

                    </div>
                ))}
            </div>

 

 

 

4.渲染组件

editor.jsx
<div class="editor-container-canvas__content" style={containerStyles.value}>
                        {
                            (data.value.blocks.map(block=>(
                                <EditorBlock block={block}></EditorBlock>
                            )))
                        }
                    </div>

 

editor-block.jsx
import { computed, defineComponent, inject } from "vue";

export default defineComponent({
    props: {
        block: { type: Object }
    },
    setup(props) {
        const blockStyles = computed(() => ({
            top: `${props.block.top}px`,
            left: `${props.block.left}px`,
            zIndex: `${props.block.zIndex}px`,

        }))
        const config = inject('config')
        console.log(config)
        return () => {
            const component = config.componentMap[props.block.key];
            const RenderComponent = component.render()
            return <div class="editor-block" style={blockStyles.value}>
                {RenderComponent}
            </div>
        }
    }
})

 

标签:const,低开,data,component,编辑器,editor,props,组件,config
From: https://www.cnblogs.com/FatTiger4399/p/17842838.html

相关文章

  • 在Vue3中使用Element-Plus分页(Pagination )组件
    在Vue3中使用Element-Plus分页(Pagination)组件开发过程中数据展示会经常使用到,同时分页功能也会添加到页面中。记:在Vue3中使用Element-Plus分页组件与表格数据实现分页交互。开始实现引入表格和分页组件的H5标签。<strong>Element-Plus分页组件使用</strong><div> <el-ta......
  • 前端学习笔记202309学习笔记第九十八天-vue2-动画特效和常见组件库3
     ......
  • WPF----日志输出组件
    输出日志需要另外下载日志专用的包比如使用Serilog将日志输出到文件需要下载以下几个包SerilogSplat.SerilogSerilog.Sinks.FileSerilog记录日志-雨水的命运-博客园(cnblogs.com)官网:https://serilog.net/ github:https://github.com/serilog ......
  • 神辅助 Cursor 编辑器,加入 GPT-4 让编码更轻松!-未来:复制粘贴工程师转向提示工程师
    在ChatGPT问世之前,我们的编码方式很多时候都是面向搜索引擎编码,需要不断地进行搜索,然后复制粘贴,俗称复制粘贴工程师。但是,随着ChatGPT的出现,这一切将彻底改变。ChatGPT是一种基于人工智能的自然语言处理模型,可以根据上下文理解人类语言并生成相应的回复。在编码方面,ChatGPT可......
  • Form表单组件封装和使用
    表单Form是中后台频繁使用的组件,以下是一个基于arcodesignvue组件库封装的表单组件。这个表单组件特点:所有配置都是直接继承组件库组件的props,无需其他文档可配置展开折叠支持响应式布局表单项支持动态隐藏插槽支持,自定义扩展组件库的良好支持,封装代码简洁优雅placeh......
  • Geany 2.0 发布使其成为更通用的文本编辑器和 IDE
    导读Geany 被认为是 Linux 上最好的PythonIDE 之一,它是一个基于GTK3工具包的开源、轻量级IDE。考虑到Geany的功能集对各种用户的吸引力,它也可以算作 Linux上Notepad++的替代品之一。现在,新版本已以“Geany2.0”的形式推出,提供了许多改进。让我们看看......
  • log4j三大组件(入门级)
    @目录......
  • javascript 自定义分页组件
    仿boostrap前端分页组件的实现一 写一个前端自定义分页组件,需要考虑以下问题  /*     需要一个<ul id="pagination"></ul>标签   total; // 总数据的数量   pageSize; // 一页显示数量   pageIndex; // 当前页   */ 二实现细节编写html......
  • Vue 该如何实现组件缓存?
    在面向组件化开发中,我们会把整个项目拆分为很多业务组件,然后按照合理的方式组织起来,那么自然会存在组件之前切换的问题,vue中有个动态组件的概念,它能够帮助开发者更好的实现组件之间的切换。但是在面对需求频繁的变化,切换组件时,动态组件在切换的过程中,组件的实例都是重新创建的,而......
  • Vue-打印组件
    组件代码:<el-buttonv-print="{id:'print-content'}"icon="el-icon-printer">打印</el-button>//插件vue-print-nb示例: ......