likes
comments
collection
share

可视化搭建项目总结(1)

作者站长头像
站长
· 阅读数 18

简介

基于vue3搭建的低代码平台,采用图形拖拽的方式,通过拖拽物料区的组件生成JSON,通过JSON渲染出页面。 可视化搭建项目总结(1)

把物料区的预览按钮拖到内容区如下所示:

可视化搭建项目总结(1)

组件的json描述

我们使用data来描述内容区的信息:

{
    // 内容区的宽高
    "container": {
        "width": 1500,
        "height": 1500
    },
    需要在内容区渲染的组件信息
    "blocks": [{
            "top": 100,
            "left": 100,
            "zIndex": 1,
            "key": "text",
            "props": {
                "text": "this is text1",
                "color": "red",
                "size": "14px"
            }
        },
        {
            "top": 200,
            "left": 200,
            "zIndex": 1,
            "text": "this is text2",
            "key": "input",
            "model": {
                "default": "username"
            }
        },
        {
            "top": 300,
            "left": 300,
            "zIndex": 1,
            "text": "this is text3",
            "key": "button",
            "props": {
                "text": "初始按钮",
                "type": "success",
                "size": "default"
            }
        }
    ]
}

组件注册

一个组件要在页面中实现,需要包括如下这些基本属性

{
    label:'文本', //物料区组件的位于左上角的说明
    preview: '预览文本', // 用于物料区的组件的渲染
    render:() => <span>渲染文本</span>, // 用于把物料区拖拽到内容区后组件的渲染
    key: 'text' // 用于json中描述组件的key对应
}

定义一个函数,返回一个对象,该对象包含一个注册函数,如下所示:

function createEditorConfig() {
  let editorConfigList = []; //存放注册的组件
  let editorConfigMap = new Map(); // 组件key和component的映射,

  return {
    editorConfigList,
    editorConfigMap.
    // 暴露一个注册函数
    register(component) {
      editorConfigList.push(component);
      editorConfigMap.set(component.key, component);
    }
  }
}

通过调用createEditorConfig()得到一个返回的对象,调用该对象的register方法即可注册组件,例如要注册一个文本组件

let registerConfig = createEditorConfig();
registerConfig.register({
  label: '文本',
  preview: () => '预览文本',
  render: () => <span>渲染文本</span>,
  key: 'text',
});

注册组件后,在左侧物料区通过遍历editorConfigList,取出每一个组件的previewlabel属性进行渲染,即可将注册的组件展示到物料区

拖拽

默认情况下,只有图片、链接和文本是可拖动的,想让其他元素变得可以拖动,需要设置元素的draggable属性为true,也可以直接写属性名draggable而不写属性值。 想要把物料区的组件拖拽到内容区,物料区的组件元素如下所示:

  {/* 左侧物料区 */}
  <div class="editor-left">
      {
         config.editorConfigList.map(component => (
           <div 
              class="editor-left-item" 
              draggable // 表示该元素可拖拽
              ondragstart={e => dragStart(e, component)}
              ondragend = {dragend}
              >
              <span>{component.label}</span>
              <div>{component.preview()}</div>
           </div>
         ))
      }
  </div>

拖动元素

在某个元素被拖动时,会(按顺序)触发以下事件

  1. dragstart
  2. drag
  3. dragend

在按住鼠标键不放并开始移动鼠标的那一刻,被拖动元素上会触发dragstart事件。dragstart事件触发后,只要目标还被拖动就会持续触发drag事件。当拖动停止时,会触发dragend事件。

放置目标元素

在把元素拖动到一个有效的放置目标上时,会依次触发以下事件(在放置目标元素上触发):

  1. dragenter
  2. dragover
  3. dragleave或drop

只要一把元素拖动到放置目标上,dragenter事件就会触发,dragenter 事件触发之后,会立即触发dragover事件,并且元素在放置目标范围内被拖动会一直触发此事件。当元素被拖动到放置目标之外,dragover事件停止触发,dragleave 事件触发。如果被拖动元素被放到了目标上,则会触发 drop 事件而不是 dragleave 事件

传输数据

event对象上暴露了一个dataTransfer对象,用于从被拖动元素向放置目标传递字符串数据,dataTransfer对象除了用于数据传输,还可以用于确定能够对被拖动元素和放置目标执行什么操作,为此,需要使用两个属性:dropEffecteffectAllowed。 本项目拖动过程中没用到传输数据的操作,只用到了dropEffect 与 effectAllowed。因此总结一下这两个属性。

dropEffect 属性可以告诉浏览器允许哪种放置行为,有4个值:

"none":被拖动元素不能放到这里。这是除文本框之外所有元素的默认值。

"move":被拖动元素应该移动到放置目标。

"copy":被拖动元素应该复制到放置目标。

"link":表示放置目标会导航到被拖动元素(仅在它是 URL 的情况下)。

为了使用 dropEffect 属性,必须在放置目标的 ondragenter 事件 处理程序中设置它。

设置dropEffect属性的同时还要设置effectAllowed。effectAllowed 属性表示对 被拖动元素是否允许 dropEffect。

"none":被拖动元素上没有允许的操作。

"copy":只允许"copy"这种 dropEffect。

"link":只允许"link"这种 dropEffect。

"move":只允许"move"这种 dropEffect。

"all":允许所有 dropEffect。

这里列出的只是一些常用的属性。

必须在dragstart事件处理程序中设置这个属性。

物料区元素拖拽到内容区的思路

在拖拽到放置目标元素上松手时,会触发放置目标元素的ondrop事件,在ondrop事件中,给data中的blocks数组添加一个block组件对象来描述该组件如何渲染。

这里的关键在于block组件的位置信息,如果只是给top和left属性设置了e.offsetY和e.offsetX值,那么在放置目标元素的一瞬间,组件的左上角对应的是鼠标的位置,为了实现组件放置的时候,组件中间直接对应着鼠标的位置 如图所示: 可视化搭建项目总结(1)

黑点代表鼠标,即我们要把实线框移动到虚线框的位置,这时候虚线框左上角的位置的计算如下

left = e.offsetX - offsetWidth / 2; //鼠标X轴位置减去元素的宽度的一半
top = e.offsetY - offsetHeight / 2; //鼠标Y轴位置减去元素的宽度的一半

但是组件的宽高如何获取呢?在没挂载组件之前,获取不到组件的宽高,因此需要在组件onMounted的钩子函数中获取组件的宽高,然后重新设置组件的left和top信息。