从零搭建低代码平台(十二)项目最终总结说明

本文介绍了低代码开发平台(LCDP),它采用Vue3+Typescript技术栈,利用scene-UI组件库构建,支持组件的可视化编辑、属性修改、事件配置等功能。用户可通过图形化界面,无需大量编码即可快速创建网页和移动应用。文章详细阐述了实现的各项功能,并展示了部分核心代码,包括组件的拖放、属性编辑、事件处理等操作。
摘要由CSDN通过智能技术生成

目录

大致介绍

实现功能

核心代码


Low-code低代码开发平台

大致介绍

低代码开发平台(LCDP)是无需编码(0代码)或通过少量代码就可以快速生成应用程序的开发平台。通过可视化进行应用程序开发的方法(参考可视编程语言),使具有不同经验水平的开发人员可以通过图形化的用户界面,使用拖拽组件和模型驱动的逻辑来创建网页和移动应用程序。

主要技术栈是Vue3+Typescript,使用了scene-UI组件库中的15个基础组件、3个场景组件。

实现功能

主要实现了:

1)组件的可视化以及可编辑化

2)改变全局属性:撤销、重做、导入、导出、预览、清空、复制、剪切、粘贴等等

3)改变组件的外部属性:添加、拖拽、删除、锁定、解锁、上移(z-Index)、下移(z-Index)、置顶(z-Index)、置底(z-Index)、组合、拆分等等

4)组件的内部属性(以按钮组件为例):X和Y坐标(在画布中的位置)、宽、高、颜色、背景色、边框颜色、边框宽度、边框半径、字体大小、字体粗细、行高、字间距、透明度、内容等等

 5)组件的事件(以按钮为例):跳转事件、alter事件等等

核心代码

import {computed, defineComponent, inject, onMounted, reactive, ref} from "vue";
import './editor.scss'
import '../assets/iconfont/iconfont.scss'
import EditorBlock from './editor-block'
import Attribute from './attr-block'
import EventList from './event-block'
import previewDemo from "@/packages/previewDemo";
import deepcopy from "deepcopy";
import {useMenuDragger} from "@/packages/useMenuDragger";
import {useFocus} from "@/packages/useFocus";
import {left} from "core-js/internals/array-reduce";
import {useBlockDragger} from "@/packages/useBlockDragger";
import {useCommand} from "@/packages/useCommand";
import Grid from "../utils/Grid"
import {useRightClick} from "@/packages/useRightClick";
import RightClick from "@/packages/rightClick"
import {ElButton, ElTabPane, ElTabs} from 'element-plus'


export default defineComponent({
    props: {
        modelValue: {type: Object}
    },
    components: {
        Grid,
    },
    emits: ['update:modelValue'],
    setup(props, ctx) {
        // 设置计算属性,以便于实现数据的双向绑定
        const data = computed({
            get() {
                return props.modelValue
            },
            set(newValue) {
                ctx.emit('update:modelValue', deepcopy(newValue))
            }
        })

        const state = {
            current: -1,
            queue: [],
            commands: {},
            commandArray: [],
            destroyArray: []
        }

        // 设置复制和剪切的内容容器,用来实现复制粘贴功能
        const copyContent = reactive({
            blockRightClickBox: false,
            containerRightClickBox: false,
            unlockRightClickBox: false,
            copyContent: [],
            startX: null,
            startY: null,
            data: data.value,
            state: state
        });
        // const copyContent = computed({
        //     get() {
        //         return copyContentReal.value
        //     },
        //     set(newValue) {
        //         ctx.emit('update:copyContent', deepcopy(newValue))
        //     }
        // })

        // 设置计算属性,用来改变和渲染画布的大小
        const containerStyles = computed(() => ({
            width: data.value.container.width + 'px',
            height: data.value.container.height + 'px',
        }))

        const config = inject('config')

        // 实现菜单拖拽功能
        const containerRef = ref(null)
        const {dragstart, dragend} = useMenuDragger(containerRef, data);


        // 实现获取焦点
        let {blockMousedown, focusData, containerMousedown, lastSelectBlock} = useFocus(data, copyContent, (e) => {
            mousedown(e)
            // console.log(JSON.stringify(attrs_style.value.attribute))
            // console.log(JSON.stringify(attrs_style.value.block))
        });

        // 实现鼠标右键点击的操作
        let {containerRightClick, blockRightClick} = useRightClick(data, copyContent)

        // 实现组件拖拽功能
        let {mousedown, markLine} = useBlockDragger(focusData, lastSelectBlock);


        const {commands} = useCommand(data, state);
        const buttons = [
            {label: '撤销', handler: () => commands.undo()},
            {label: '重做', handler: () => commands.redo()},
            {label: '导出', handler: () => commands.output()},
            {label: '保存', handler: () => commands.save()},
            {label: '预览', handler: () => commands.preview()},
            {label: '清空', handler: () => commands.clear()},
            {label: '删除', handler: () => commands.remove()},
            {label: '置顶', handler: () => commands.top()},
            {label: '置底', handler: () => commands.bottom()},
            {label: '锁定', handler: () => commands.lock()},
            {label: '解锁', handler: () => commands.unlock()},
            {label: '组合', handler: () => commands.combine()},
            {label: '拆分', handler: () => commands.divide()},
        ]

        return () => <div class="editor">

            <div class="editor-left">
                <img src="scene-UI.png" style="margin:auto; width: 250px; height: 100px"/>
                <div class="editor-left-form">
                    {/*根据注册列表  渲染对应的内容*/}
                    <ElTabs class="editor-left-tabs" type="card">
                        <ElTabPane label="基础组件">
                            {config.componentList.map((component, index) => {
                                if (index <= 11) {
                                    return (
                                        <div
                                            class='editor-left-item'
                                            draggable
                                            onDragstart={e => dragstart(e, component)}
                                            onDragend={dragend}
                                        >
                                            <span>{component.label}</span>
                                            <div>{component.preview()}</div>
                                        </div>
                                    )
                                }
                            })}
                        </ElTabPane>
                        <ElTabPane label="Scene结合组件">
                            {config.componentList.map((component, index) => {
                                if (index > 11) {
                                    return (
                                        <div
                                            class='editor-left-item'
                                            draggable
                                            onDragstart={e => dragstart(e, component)}
                                            onDragend={dragend}
                                        >
                                            <span>{component.label}</span>
                                            <div>{component.preview()}</div>
                                        </div>
                                    )
                                }
                            })}
                        </ElTabPane>
                    </ElTabs>
                </div>
            </div>

            <div class="editor-top">
                {buttons.map((btn, index) => {
                    // console.log(JSON.stringify(data.value))
                    let deleteDisabled = true
                    let topDisabled = true
                    let bottomDisabled = true
                    let lockDisabled = true
                    let unlockDisabled = true
                    data.value.blocks.forEach((block, idx) => {
                        if (block.focus === true && block.lock === false) {
                            deleteDisabled = false
                            topDisabled = false
                            bottomDisabled = false
                            lockDisabled = false
                        }
                        if (block.focus === true && block.lock === true) {
                            unlockDisabled = false
                        }
                    })
                    // console.log(index)
                    if (index === 6) {
                        // 删除
                        return <ElButton class="editor-top-button" disabled={deleteDisabled} onClick={btn.handler}>
                            <span class={btn.label}>{btn.label}</span>
                        </ElButton>
                    } else if (index === 7) {
                        return <ElButton class="editor-top-button" disabled={topDisabled} onClick={btn.handler}>
                            <span class={btn.label}>{btn.label}</span>
                        </ElButton>
                    } else if (index === 8) {
                        return <ElButton class="editor-top-button" disabled={bottomDisabled} onClick={btn.handler}>
                            <span class={btn.label}>{btn.label}</span>
                        </ElButton>
                    } else if (index === 9) {
                        return <ElButton class="editor-top-button" disabled={lockDisabled} onClick={btn.handler}>
                            <span class={btn.label}>{btn.label}</span>
                        </ElButton>
                    } else if (index === 10) {
                        return <ElButton class="editor-top-button" disabled={unlockDisabled} onClick={btn.handler}>
                            <span class={btn.label}>{btn.label}</span>
                        </ElButton>
                    } else if (index === 11) {
                        return <ElButton class="editor-top-button" disabled={true} onClick={btn.handler}>
                            <span class={btn.label}>{btn.label}</span>
                        </ElButton>
                    } else if (index === 12) {
                        return <ElButton class="editor-top-button" disabled={true} onClick={btn.handler}>
                            <span class={btn.label}>{btn.label}</span>
                        </ElButton>
                    } else {
                        return <ElButton class="editor-top-button" onClick={btn.handler}>
                            <span class={btn.label}>{btn.label}</span>
                        </ElButton>
                    }
                })}

            </div>
            <div class="editor-right">
                {/*产生滚动条*/}
                <div class="editor-right-form">
                    {/*产生组件属性表单*/}
                    <ElTabs class="editor-right-form-tabs" type="card">
                        <ElTabPane label="属性"><Attribute v-model={data.value}/></ElTabPane>
                        <ElTabPane label="事件"><EventList v-model={data.value}/></ElTabPane>
                        <ElTabPane label="动画">暂未实现</ElTabPane>
                    </ElTabs>

                </div>
            </div>

            <div class="editor-container">
                {/*产生滚动条*/}
                <div class="editor-container-canvas">
                    {/*产生内容区域*/}
                    <div
                        class="editor-container-canvas_content"
                        style={containerStyles.value}
                        ref={containerRef}
                        onmousedown={containerMousedown}
                        oncontextmenu={containerRightClick}
                    >
                        <RightClick v-model={copyContent}/>
                        {/*网格线*/}
                        <Grid/>
                        <previewDemo v-model={data.value}/>


                        {
                            (data.value.blocks.map((block, index) => {
                                // console.log(index)
                                return <EditorBlock
                                    // class={"iconfont icon-suo"}
                                    // cursor="move"
                                    class={block.lock ? 'iconfont icon-suo' : ''}
                                    class={block.focus ? 'editor-block-focus' : ''}
                                    block={block}
                                    data={data}
                                    index={index}
                                    onmousedown={(e) => e.target.className === 'editor-block' || e.target.className === 'editor-block editor-block-focus' || e.target.className === 'editor-block iconfont icon-suo' ? blockMousedown(e, block, index) : ''}
                                    onmouseover={(e) => e.target.className === 'editor-block' || e.target.className === 'editor-block editor-block-focus' || e.target.className === 'editor-block iconfont icon-suo' ? e.target.style.cursor = block.moveSign : ''}
                                    // onmouseover={(e) => e.target.children.length === 0 ? '' : e.target.children[0].style.cursor ='move'}
                                    // onmouseover={(e) => console.log(e.target.className)}
                                    oncontextmenu={(e) => blockRightClick(e, block)}
                                />
                            }))
                        }
                        {markLine.x !== null && <div class='line-x' style={{left: markLine.x + 'px'}}/>}
                        {markLine.y !== null && <div class='line-y' style={{top: markLine.y + 'px'}}/>}

                    </div>
                </div>
            </div>
        </div>
    }
})
  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值