低代码主要功能解决方案| 青训营笔记

144 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的的第17天

1.拖拽解决方案

Ⅰ.使用h5标签拖拽功能:dragable="true"

  被拖拽元素上触发的事件:

  1.ondragstart - 用户开始拖动元素时触发

  2.ondrag - 元素正在拖动时触发

  3.ondragend - 用户完成元素拖动后触发

  目标元素上触发的事件:

  1.ondragenter - 当被鼠标拖动的对象进入其容器范围内时触发此事件

  2.ondragover - 当某被拖动的对象在另一对象容器范围内拖动时触发此事件

  3.ondragleave - 当被鼠标拖动的对象离开其容器范围内时触发此事件

  4.ondrop - 在一个拖动过程中,释放鼠标键时触发此事件

  另外需要的知识点就是event对象中的preventDefault()。

ondragover中一定要执行preventDefault(),否则ondrop事件不会被触发。另外,如果是从其他应用软件或是文件中拖东西进来,尤其是图片的时候,默认的动作是显示这个图片或是相关信息,并不是真的执行drop。此时需要用用documentondragover事件把它直接干掉。

拖动时组件瞄定中心:

// 拖动的时候,让被拖动元素放置位于鼠标的中间
    onMounted(() => {
let { offsetWidth, offsetHeight } = blockRef.value;
if (props.block.alignCenter) {
props.block.left = props.block.left - offsetWidth / 2;
props.block.top = props.block.top - offsetHeight / 2;
props.block.alignCenter = false;
}
props.block.width = offsetWidth;
props.block.height = offsetHeight;
    });

拖拽方法参考:

blog.csdn.net/hjc256/arti…

Ⅱ.自定义拖拽事件:

{config.componentList.map((component) => (
          <div
            class="editor-left-item"
            draggable
            onDragstart={e => dragstart(e, component)}
            onDragend={dragend}
          >
            <span>{component.label}</span>
            {component.preview()}
          </div>
        ))}

const dragstart = (e, component) => {

    containerRef.value.addEventListener("dragenter", dragenter);
    containerRef.value.addEventListener("dragover", dragover);
    containerRef.value.addEventListener("dragleave", dragleave);
    containerRef.value.addEventListener("drop", drop);
    currentComponent = component;
    // 发布start事件
    events.emit("start");
  };
  const dragend = (e, component) => {
    containerRef.value.removeEventListener("dragenter", dragenter);
    containerRef.value.removeEventListener("dragover", dragover);
    containerRef.value.removeEventListener("dragleave", dragleave);
    containerRef.value.removeEventListener("drop", drop);
    // 发布end事件
    events.emit("end");
  };
  return { dragstart, dragend };
}

2.页面元素放置,布局解决方案

Ⅰ.通过拖拽事件,鼠标松开时,自动放入div中对齐

ondragover根据拖拽的组件大小生成标准div框与瞄点框遮罩,ondrop将标签插入div框内且自动对齐

 function drop(e) {
            e.preventDefault();
            
            let id = e.dataTransfer.getData('id');
            e.target.appendChild(document.getElementById(id));
        }

Ⅱ.全画布自由放置,组件靠近已有标签自动生成瞄准线

ondragover时在画布生成已有标签,参考线,根据拖拽鼠标位置获取坐标,鼠标松开后根据组件坐标插入组件,

lines: (() => {
        const { unfocused } = focusData.value;
        const lines = { x: [], y: [] }; // 显示对齐辅助 的位置, y数组存储横线,x数组存贮竖线
        [
          ...unfocused,
          {
            top: 0,
            left: 0,
            width: component.value.container.width,
            height: component.value.container.height,
          },
        ].forEach((block) => {
          const {
            top: TargetTop,
            left: TargetLeft,
            width: TargetWidth,
            height: TargetHeight,
          } = block;
          // 计算横线
          lines.y.push({ showTop: TargetTop, top: TargetTop }); //拖动元素顶和目标元素顶 对齐
          lines.y.push({ showTop: TargetTop, top: TargetTop - moveHeight }); // 拖动元素底部和目标元素顶 对齐
          lines.y.push({
            showTop: TargetTop + TargetHeight / 2,
            top: TargetTop + TargetHeight / 2 - moveHeight / 2,
          }); //拖动元素和目标元素 水平中心对齐
          lines.y.push({
            showTop: TargetTop + TargetHeight,
            top: TargetTop + TargetHeight,
          }); // 拖动元素顶 和目标元素底部 对齐
          lines.y.push({
            showTop: TargetTop + TargetHeight,
            top: TargetTop + TargetHeight - moveHeight,
          }); // 拖动元素底部 和目标元素底部  对齐

          // 计算竖线
          lines.x.push({ showLeft: TargetLeft, left: TargetLeft }); // 拖动元素左 对齐 目标元素左
          lines.x.push({
            showLeft: TargetLeft + TargetWidth,
            left: TargetLeft + TargetWidth,
          }); // 拖动元素左 对齐 目标元素右
          lines.x.push({
            showLeft: TargetLeft + TargetWidth / 2,
            left: TargetLeft + TargetWidth / 2 - moveWidth / 2,
          }); //拖动元素中 对齐 目标元素中
          lines.x.push({
            showLeft: TargetLeft + TargetWidth,
            left: TargetLeft + TargetWidth - moveWidth,
          }); //拖动元素右 对齐 目标元素右
          lines.x.push({ showLeft: TargetLeft, left: TargetLeft - moveWidth }); // 拖动元素右 对齐 目标元素左
        });
        // console.log(lines);
        return lines;
      })(),

\

3.预览解决方案

Ⅰ.点击预览按钮,转换组件渲染方式,禁用编辑

setup(props, ctx) {
    // 预览的时候内容不能再操作,可以点击输入内容方便看效果
    const previewRef = ref(false)
    const editorRef = ref(true)
    }
//预览按钮:
   {
        label: () => previewRef.value ? '编辑' : '预览',
        icon: () => previewRef.value ? <Hide /> : <View />,
        handler: () => {
          previewRef.value = !previewRef.value
          clearBlockFocus()
        }
   }

4.图片视频上传解决方案

使用vue+element ui的el-upload组件,后台设置上传api且返回url

m.jb51.net/article/233…

\

5.修改属性解决方案

Ⅰ记录最后选择的组件,获取其属性值

将属性值按类型,渲染在属性栏内,实时更改

// 最后选择的组件
  const lastSelectBlock = computed(() => data.value.blocks[selectIndex.value])


<div class="editor-right">
        <EditorOperator
          block={lastSelectBlock.value}
          data={data.value}
          updateContainer={commands.updateContainer}
          updateBlock={commands.updateBlock}
        />
      </div>

6.发布解决方案

输出Json文件:

7.撤销事件:

使用mitt插件,引入event记录事件(如拖拽事件)前后的状态,加入撤销按钮

import mitt from 'mitt'

export const events = mitt() // 导出一个发布订阅的对象