H5编辑器整体思路(三):组件的行为

814 阅读3分钟

既然说到编辑器,那就肯定脱离不了几个功能:拖拽、放大、缩小、辅助线等功能,本节,我就以我的编辑器的思路讲讲组件的行为功能

我们简单回忆一下,我在H5编辑器整体思路(一):前言中提到的组件的代码


  <EditElement
    v-for="item in activePage.elements"
    :key="item.uuid + 'i'"
    :uuid="item.uuid"
    :defaultStyle="item.commonStyle"
    :style="getCommonStyle(item.commonStyle)"
    @handleElementClick="handleElementClick(item.uuid, item)"
    v-show="!item.isHide"
    @resize="handleElementResize"
    :active="item.uuid === activeElementUUID"
    :isPrivew="false"
  >
    <component
      :is="item.elName"
      class="element-on-edit-pane"
      v-bind="{
        ...item.propsValue,
        value: item.value,
        uuid: item.uuid
      }"
      :textS.sync="item.propsValue.text"
    />
  </EditElement>

每个元素的组件被一个EditElement组件包在里面,这里做的目的是在每个组件外层包一个壳子,这个壳子的功能就是来承载每个组件的点击事件、拖拽、放大、缩小等动作行为。大概的效果图如下:

image.png

1、拆解editElement

先说思路在上代码。

思路:当每个组件生成之后,动态给每个组件外新增个壳子,壳子里主要包含了一个旋转的div,四个位于元素的左上、右上、左下、右下四个div。旋转就不用多说了,点击旋转按钮后进行旋转,四个div分别控制四个角的缩放功能,外层最大的的壳子来控制它的移动

整体代码:

<div
    class="edit-element"
    @click="handleTopWrapperClick"
    @mousedown="handleMouseDownOnElement"
    :class="{ active: active && !isPrivew }"
  >
    <div class="yincang" ref="yincang"></div>
    <template v-if="!isPrivew">
      <div class="edit-shape-rotate" :style="getPosition" v-show="this.active">
        <div class="edit-shape-point-rotate" @mousedown="handleMoseRotate">
          <svg-icon
            iconName="rotate"
            :iconWidth="16"
            :iconHeight="16"
          ></svg-icon>
        </div>
      </div>
      <div
        class="edit-shape-point"
        v-for="item in active ? pointList : []"
        :key="item"
        :id="item"
        @mousedown="handleMouseDownOnPoint(item, $event)"
        :style="{
          ...getPointStyle(item),
          transfrom: 'rotate(' + rotate + 'deg)'
        }"
      ></div>
    </template>
    <slot></slot>
  </div>

旋转按钮代码:

<div class="edit-shape-rotate" :style="getPosition" v-show="this.active">
    <div class="edit-shape-point-rotate" @mousedown="handleMoseRotate">
      <svg-icon
        iconName="rotate"
        :iconWidth="16"
        :iconHeight="16"
      ></svg-icon>
    </div>
</div>

四个角的按钮:

 <div
    class="edit-shape-point"
    v-for="item in active ? pointList : []"
    :key="item"
    :id="item"
    @mousedown="handleMouseDownOnPoint(item, $event)"
    :style="{
      ...getPointStyle(item),
      transfrom: 'rotate(' + rotate + 'deg)'
    }"
  ></div>

2、元素的拖拽

元素拖拽是比较简单的,就是使用了鼠标的点击事件和鼠标移动事件来计算它的位置,具体思路如下

image.png

代码如下:

    pos.top = Math.round(currY - startY + Number(startTop));
    pos.left = Math.round(currX - startX + Number(startLeft));

3、放大、缩小

基于鼠标的移动事件来计算等比例放大缩小,多说无益直接上思路图

image.png

从上述的图看的出来这次有点点复杂,先说下需求,有四个角可以点击拖拽缩放,leftTop、rightTop、leftBottom、rightBottom

鼠标往右的话 鼠标的clientX 值越大,鼠标向下的时候 鼠标的clientY 值越大,这里就不细说,可以自己打印鼠标事件,所以这里就有个结论:

image.png

image.png 四个角都有自己的名字:lt、rt、lb、rb

按上述我画的图,所以接下来的代码是这样的

let disX = currX - startX;
let disY = currY - startY;

let hasT = /t/.test(str);
let hasB = /b/.test(str);
let hasL = /l/.test(str);
let hasR = /r/.test(str);

let newHeight = +height + (hasT ? -disY : hasB ? disY : 0);
let newWidth = +width + (hasL ? -disX : hasR ? disX : 0);

hasT代表的是是否是从上开始拖拽

hasB代表的是否是从下开始拖拽

hasL代表的是是否从左开始拖拽

hasR代表的是是否从右开始拖拽

现在拖拽的部分我们大致了解了,这样就可以获取到拖拽后元素的宽高,但是元素的定位还没出来,我们需要做出如下的需求:

2023-02-27_16-19-11 (1).gif

大概解题思路:

img-3357.jpg

因为要等比例缩放所以代码如下:

pos.width = newWidth;
pos.height = Math.round(((pos.width * oldheight) / oldwidth) * 100) / 100;

因为缩放过程中需要动态更改它的定位,根据上面的思路图可以得到以下代码

if (hasT) {
    pos.top = top + (oldheight - pos.height);
  }
  if (hasL) {
    pos.left = left + (oldwidth - pos.width);
  }

简单的等比例缩放就完结。以为就这样完了?

2023-02-27_17-09-27 (1).gif

还有这样的

2023-02-27_17-10-22 (1).gif

这里我简单介绍下文本的拖拽缩放,视频的拖拽缩放丢给大家自己思考一下哈

可以根据效果图,我们的需求是:文本只可以左右横向拖拽,当拖拽到宽度为单个文字的时候就不能再缩小,所以高度不变,只考虑宽度

pos.width = newWidth > firstW ? Math.round(newWidth) : firstW;

firstW在这里指的是单个文字的 fontSize 的1.5倍,大家不要以为是初始宽度

newWidth大于最小宽度 firstW则以新宽度为准否则按照 firstW为准

let newDisX
// 原始宽度 - 鼠标移动宽度 = 剩余的宽度
let diffXFlag = oldwidth - disX;
//每次移动都记录下,当前剩余宽度是否大于 firstW,如果大于 就将鼠标移动宽度赋值给 newDisX,直到 diffXFlag == firstW的时候 newDisX停止赋值,这个时候的newDisX代表缩放时鼠标的最大移动距离
diffXFlag > firstW && (newDisX = disX);

conentL = hasL ? (diffXFlag <= fw ? newDisX : disX) : 0;
pos.left = Math.round(left + conentL);

image.png

本节组件的拖拽、放大、缩小分享结束,有问题可以发评论一起讨论。

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 3 天,点击查看活动详情