第 11 章:可视化编辑器实现
“所见即所得 (WYSIWYG)。如果不‘得’,那就是 Bug。”
可视化编辑器 (src/components/ActivityDesign) 是本项目的核心亮点。它允许用户在手机屏幕上直接拖拽、配置活动页面。
11.1 编辑器架构设计
编辑器由三个核心区域组成:
- 画布区 (Canvas): 位于屏幕中央,实时展示页面效果。支持“编辑模式”和“预览模式”切换。
- 组件库 (Library): 点击右下角 FAB 按钮弹出。展示所有可用组件(文本、图片、视频等)。
- 属性面板 (Property Panel): 点击画布上的组件弹出。用于修改当前组件的文字、颜色、图片等属性。
状态流转
graph TD
Library[组件库] -->|Select| Canvas[画布]
Canvas -->|Tap Component| Property[属性面板]
Property -->|Confirm| Canvas
Canvas -->|Save| DB[数据库]
11.2 拖拽排序实现
在手机上实现拖拽排序(Drag & Drop)是个技术活。 本项目采用了简化版排序逻辑:
- 选中: 点击组件,外层出现蓝色边框和工具栏(上移、下移、复制、删除)。
- 上移/下移: 交换数组中相邻元素的索引。
typescript const handleUp = () => { const idx = selectedIndex.value if (idx <= 0) return // 数组解构交换,ES6 的魔法 ;[list[idx], list[idx-1]] = [list[idx-1], list[idx]] }优化方向: 如果追求极致体验,可以使用
movable-area+ 触控算法实现自由拖拽,但在移动端,点击“上/下移”按钮往往比手指按住拖动更精准,不易误触。
11.3 实时预览与保存
预览模式 (Preview Mode)
编辑器维护了一个 isPreview 状态。
isPreview = false: 组件外层包裹边框,显示工具栏,点击触发编辑。isPreview = true: 隐藏所有辅助 UI,只展示最终效果,点击触发实际业务逻辑(如跳转)。
数据回显与保存
- 回显: 父组件将数据库里的
components数组传给编辑器,编辑器深拷贝一份到本地ref。 - 保存: 编辑器触发
emit('update:components')或emit('save'),将修改后的数组传回父页面,父页面调用云函数保存。
11.4 组件属性编辑器
当用户点击“文本组件”时,弹出的属性面板必须也是动态的。
我们为每个组件类型封装了对应的属性表单:
property/Text.vue: 包含输入框(内容)、滑块(字号)、颜色选择器。property/Image.vue: 包含图片上传组件。
父子组件通信:
- Canvas 选中组件 ->
selectedComponent。 - 传给
<PropertyPanelPopup :component="selectedComponent">。 - Popup 根据
component.type渲染对应的 Property 表单。 - 表单修改后,
emit('confirm', newConfig)。 - Canvas 更新
components数组中的对应项。
本章小结: 我们成功把复杂的 JSON 编辑过程,封装成了符合直觉的图形化操作。用户不需要懂代码,只需要会点点点,就能做出漂亮的页面。下一章,我们将讲解组件渲染引擎,看看这些配置好的数据是如何变成用户眼中的最终画面的。