这是我参与「第四届青训营 」笔记创作活动的的第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。此时需要用用document的ondragover事件把它直接干掉。
拖动时组件瞄定中心:
// 拖动的时候,让被拖动元素放置位于鼠标的中间
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;
});
拖拽方法参考:
Ⅱ.自定义拖拽事件:
{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
\
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() // 导出一个发布订阅的对象