H5编辑器整体思路(一):前言

1,622 阅读6分钟

现在很多公司都在搞低代码平台,这已经是一个老生常谈的一些话题了,今天我也来讲讲我们的业务驱动的“低代码”平台。低代码平台本身概念出来的时候就是以快速低成本为导向输出一些统一规范的平台。但是可能有很多人跟我一样在公司中写着写着就被业务带跑了,有些功能属性带有强烈的业务属性。但是大家也要理解,好的工具肯定是为业务赋能,如果不能赋能它的价值很难在公司被体现出来

这篇文章不算是低代码平台的分享充其量算是个小型的编辑器

划重点 :这里不是低代码平台,只是单纯的将我的编辑器进行分享

1、前言

2020年年底,我第一次接触到快速编辑器,是通过github的开源组件quark,当然我当时也不知道这是个什么东西,我就去看了他的源码,其实看不懂,因为第一次接触这种类型(自己当时还非常的菜),在后续简单的接触以后,我貌似理解了它的大概原理(数据驱动视图),接到需求就开始梭哈

2、要做成什么样子

当我想找产品问你到底要做成什么样子,他给我罗列了A、B、C等H5编辑器的网址,然后给我说我要做成他们的合体,我一脸懵逼的看向了他,他接着说“我要A的序列帧功能、我要B的的旋转功能、我要某云盘的上传下载文件功能”,最后他又补充了一句我想做线上PS或者PPT的那样的软件

好了上面讲了那么多有趣的开始,我们就说说我们如何实现的,目前该项目还未暂时开源,所以我只能给各位看看效果图以及实现的思路

3、效果图

PC编辑器

2023-02-22_16-37-08 (1).gif

移动端预览

2023-02-22_15-38-31 (1).gif

4、项目目录详解以及功能单

项目目录:

- src
  - api 所有ajax请求管理
    - common.js 编辑器接口管理
    - h5List.js h5List接口管理

  - assets 醒目静态文件管理
  - commonents 项目所有组件 详细介绍请看功能

  - plugins 编辑器所用元素组件
    - animate 帧动画组件
    - bg-music 背景音乐组件
    - button 按钮组件
    - form 留资组件
    - hottag 热点组件
    - iframe 外链组件
    - iamge 图片组件
    - image-carousel 幻灯片组件
    - input 输入框组件
    - menu 经典菜单组件
    - menu-img 图片组件
    - text 文本组件
    - textarea 富文本编辑器
    - video 视频组件
    - vote 投票组件
  - router vue router路由
  - store vuex数据管理中心
    - modules 所有模块的数据管理
      - editor.js 项目中所有的数据管理
    - getter.js vuex计算数据管理
    - index.js 实例化vuex
  - theme element-ui 统一样式风格
  - utils 项目所有工具函数管理
    - animateCssData.js 动画列表集合
    - autoImport.js 全局自动化注册component工具
    - common.js 全局公共方法
    - DataModel.js 数据结构
    - down.js 下载工具
    - error.js 报错工具
    - eventBus.js eventBus工具
    - Gutils.js 全局公共方法挂载到VUE的实例上
    - method.js axios的请求方式封装
    - request.js 封装axios
    - runAnimations.js 播放动画函数
    - threeMessage.js 手写message函数
  - views
    - editViews 编辑器模块
      - prodicts 编辑器项目文件夹
        - index.vue 编辑器入口
      - componentList.js 所有元素组件的列表
      - h5List.vue h5列表
    - index.vue 项目入口
  - app.vue 大家都懂
  - main.js 整个项目入口

该项目的功能清单:

- 登录 / 注销
 - 采用统一NPM包

- 权限验证
  - 采用统一NPM包

- 多环境发布
  - dev
  - test
  - prod

- 所有功能
  - 创建组件
  - 生成预览二维码
  - 创建常规页面和长页面
  - 页面基础配置
  - 页面滑动和页面全局配置
  - Svg 图标
  - 画布的展示功能
  - 元素的拖拽缩放、元素的自动定位
  - 图片组件
  - 视频组件
  - 幻灯片组件
  - 留资组件
  - 下载功能

- 組件(components)
  - attr
   - 帧动画 属性配置
   - 留资组件 属性配置
   - 图片组件 属性配置
   - 幻灯片组件 属性配置
   - index
   - 文本组件 属性配置
   - 视频组件 属性配置
   - 投票组件 属性配置
  - dialog
   - 弹窗组件 属性配置
   - 地图弹窗 属性配置
  -prompt
   - 一级提示
   - 二级提示
   - 三级提示
  - 颜色编辑器 组件
  - 头部控制栏 组件
  - 自定义switch 组件
  - 编辑动画 组件
  - 编辑元素 组件
  - 编辑页面 组件
  - 画布 组件
  - 事件编辑 组件
  - 工具栏 组件
  - 自定义input 组件
  - 新版本素材库 组件
  - 素材取消 组件
  - 素材使用 组件
  - 素材预览 组件
  - 页面属性编辑 组件
  - 左侧页面控制栏 组件
  - 预览和设置 组件
  - 发布项目 组件
  - h5列表中二维码 组件
  - 页面滑动效果配置 组件
  - 元素大小控制input 组件
  - 自定义上传素材 组件
  - 投票组件数据统计 阻击N
- 混入(mxins)
  - 公共属性配置混入 (比如 元素的宽高 位置 浮动定位)
  - 字体列表混入 (自定义字体列表)

5、代码细节

整体编辑器的组件代码是由以下代码形成的

    <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>

几个关键词:activePage,elements

activePage 代表的是当前页面

elements 代表的是当前页面的所有元素,

其实整体编辑器就是在一个页面上有无数个元素进行组合然后生成的一个页面,通过动态更改每个元素或者每个页面来支撑它的编辑功能

组件的呈现采用了vue的动态component的语法来实现的,每个组件的入参都是item.propsValue,接下来我们先来看下组件的数据结构是怎么样的

{
  elName: '', // 组件类型 xx-image
  // 组件的名字
  ename: '',
  // add zhou 0617 end
  animations: [], // 动画
  // 样式
  commonStyle: {
    position: 'absolute',
    width: 375,
    height: 30,
    top: 200,
    left: 0,
    rotate: 0,
    paddingTop: 0,
    paddingLeft: 0,
    paddingRight: 0,
    paddingBottom: 0,
    marginTop: 0,
    marginLeft: 0,
    marginRight: 0,
    marginBottom: 0,
    borderWidth: 0,
    borderColor: '',
    borderStyle: 'solid',
    borderRadius: 0,
    boxShadow: '',
    fontSize: 14,
    fontWeight: 500,
    lineHeight: 1.4,
    letterSpacing: 0,
    textAlign: 'center',
    color: '#000000',
    backgroundColor: '',
    backgroundImage: '',
    backgroundSize: 'cover',
    opacity: 1,
    zIndex: 1
  }, // 公共样式
  events: [], // 事件
  propsValue: {}, // 属性参数
  value: '', // 绑定值
  valueType: 'String' // 值类型
}

页面的数据结构:

{
  name: 1, // 页面名称
  elements: [],// 页面元素列表
  coverImage: '', // 页面截图
  // 页面的公共样式
  commonStyle: {
    backgroundColor: '#ffffff',
    backgroundImage: '',
    backgroundImageName: '请选择图片',
    backgroundSize: 'cover',
    attrPage: false,
    pageBg: {
      pageW: 375,
      pageH: 724,
      pageX: 0,
      pageY: 0
    }
  },
  // 页面的公共配置
  config: {
    activeAnimate: 'pinghua',
    isDisableCurrentPageScroll: false // 是否禁用当前页面的首饰滑动
  }, // 翻页动效
  type: 'normal', // normal正常页面 lang 长页面 psd
  isForAll: false // 是否应用到所有页面
}

大体的数据结构是这样子设计,接下来我们列一下一个元素从无到有需要经历哪几步

1、选择元素比如 图片类、视频、文本类、表单类、banner类

2、初始元素的默认属性,比如长宽高、透明度、位置等等

3、元素的选中、移动、拖拽、放大、缩小等action

围绕这个目标我们可以细分代码,具体实现由后续讲解

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