授权转载自:石头人汉考克,https://juejin.cn/post/6844904083120193543
公司经常为了活动推广营销,拉新留存,制作临时活动页面,且组件大体相似,为了提高运营的工作效率,减少开发成本,基于此开发一个活动可视化搭建项目,让运营可以通过,点击和拖拽组件,选择或导入数据的的方式,快速生成活动页面上线,在此做一个小小的总结。
大体流程是:
创建 -> 编辑 -> 保存 -> 发布 -> 展示
核心:
维护一个obj,保存着个组件的父子关系,像一个node树
,每个组件都有唯一的ID,举例如下
const nodeTree = {
id: 'component0',
name: 'rootContainer',
children: [
{
id: 'component1',
name: 'header'
},
{
id: 'component2',
name: 'content',
children: [],
}
]
}
dragStart
(拖动开始),dragOver
(拖动到可释放区),dragEnd
(拖动结束) ,drop
(放下)时进行相应的数据传递和增删改查的动作export const relativePositionJudge = (cur, box, isDrop, direction) => {
const rect = box.getBoundingClientRect();
let offset = null;
if(direction) {
offset = {
x: rect.width / 2,
y: 0,
};
} else {
offset = {
x: 0,
y: isDrop ? rect.height / 4 : rect.height / 2,
};
}
const point = {
x: cur.clientX,
y: cur.clientY,
};
// up
const rect1 = {
x: rect.x + offset.x,
y: rect.y,
w: rect.width - (offset.x * 2),
h: offset.y,
};
// down
const rect2 = {
x: rect.x + offset.x,
y: (rect.y + rect.height) - offset.y,
w: rect.width - (offset.x * 2),
h: offset.y,
};
// inside
const rect3 = {
x: rect.x + offset.x,
y: rect.y + offset.y,
w: rect.width - (offset.x * 2),
h: rect.height - (offset.y * 2),
};
// front
const rect4 = {
x: rect.x,
y: rect.y,
w: offset.x,
h: rect.height,
};
// behind
const rect5 = {
x: rect.x + rect.width - offset.x,
y: rect.y,
w: offset.x,
h: rect.height,
};
let pos = null;
if (pointInRect(point, rect1)) pos = 'up';
if (pointInRect(point, rect2)) pos = 'down';
if (pointInRect(point, rect3)) pos = 'inside';
if (pointInRect(point, rect4)) pos = 'front';
if (pointInRect(point, rect5)) pos = 'behind';
return pos;
};
const pointInRect = (point, rect) => {
return point.x >= rect.x && point.y >= rect.y && point.x <= rect.x + rect.w && point.y <= rect.y + rect.h;
};
cur
为当前拖拽的组件,可通过其获取鼠标当前坐标box
为当前悬停区域,通过getBoundingClientRect
方法获取宽高及位置isDrop
为当前区域是否可放置,direction
为当前区域元素的排列方向,通过两者设置,横向或纵向的偏移量大小,请看下图演示
每一类定制组件都有唯一的name名,每一个组件在node树中被创建时也有唯一id,方便后期的编辑和渲染,
遍历node树递归调用主渲染文件,根据组件name名和相应数据,渲染出对应组件
活动页面上会涉及很多文字,用户想修改,有几种方法
以上两种可能都不太直观,也比较麻烦
就想到了使用contenteditable
属性,给标签加上后,可直接修改文字,可设置双击修改,延时保存,并设置防抖,大多数组件都会存在此需求,直接标签绑定事件比较麻烦,因此设置了全局绑定事件监听,控制注册和及时销毁
请看下图演示
每一次操作后,都存储一下node树,并放入回退队列,,通过指向队列的上一个或下一个来实现回退和取消回退,通过并限制队列长度,控制浏览器内存使用
问题:
所以此想法被PASS,每创建保存一个活动页,都会在服务器固化的生成唯一的html文件和静态资源,保证不被影响
优点:
总体是满足了产品需求,同时从三方面考虑