好傢伙,
0.程式碼已開源
Fattiger4399/lowcode-demo: 一個簡單的低程式碼編輯器 技術棧:Vue3 element-plus jsx (github.com)
該章實現的效果:元件從物料區到畫布的拖拽
1.分析
先來分析,滑鼠點選物料區的某個元件,再將其拖拽到畫布這個過程
我們如何實現元件的拖拽??
- 滑鼠按下元件時獲取當前選中元件的資訊
- 繫結滑鼠的移動和鬆開事件,鬆開時在畫布上渲染當前塊。
- 將拖拽的元件渲染在畫布上。
<div>
<div class="editor-left">
{/* 根據註冊列表 渲染對應的內容 可以實現h5的拖拽*/}
{config.componentList.map(component => (
<div class="editor-left-item"
draggable
onDragstart={e => dragstart(e, component)}
onDragend={dragend}
>
<span>{component.label}</span>
<div>{component.preview()}</div>
</div>
))}
</div>
<div class="editor-top">選單欄</div>
<div class="editor-right">屬性控制欄目</div>
<div class="editor-container">
<div class="editor-container-canvas">
{/* 產生內容 */}
<div class="editor-container-canvas__content"
style={containerStyles.value}
ref={containerRef}
onMousedown={containerMousedown}>
{
(data.value.blocks.map(block => (
<EditorBlock
class={block.focus ? 'editor-block-focus' : ''}
block={block}
onMousedown={(e) => blockMousedown(e, block)}
></EditorBlock>
)))
}
</div>
</div>
</div>
</div>
2.處理物料區
import { registerConfig as config } from './utils/editor-config'
config為我們的元件登錄檔資訊
const { dragstart, dragend } = useMenuDragger(containerRef, data)
{config.componentList.map(component => ( <div class="editor-left-item" draggable onDragstart={e => dragstart(e, component)} onDragend={dragend} > <span>{component.label}</span> <div>{component.preview()}</div> </div> ))}
此處為物料元件新增onDragstart和onDragend事件
useMenuDragger.js
export function useMenuDragger(containerRef,data){
let currentComponent = null;
const dragenter = (e) => {
e.dataTransfer.dropEffect = 'move'; //h5的拖動圖示
}
const dragover = (e) => {
e.preventDefault();
}
const dragleave = (e) => {
e.dataTransfer.dropEffect = 'none';
}
const drop = (e) => {
//先留在這
console.log(e.offsetY)
console.log(e.offsetX)
let blocks = data.value.blocks;//內部已渲染的元件
data.value = {
...data.value, blocks: [
...blocks,
{
top: e.offsetY,
left: e.offsetX,
zIndex: 1,
key: currentComponent.key,
alignCenter: true //鬆手時劇中
}
]
}
currentComponent = null
}
const dragstart = (e, component) => {
//dragenter進入元素中
containerRef.value.addEventListener('dragenter', dragenter)
containerRef.value.addEventListener('dragover', dragover)
containerRef.value.addEventListener('dragleave', dragleave)
containerRef.value.addEventListener('drop', drop)
currentComponent = component
}
const dragend = (e) => {
containerRef.value.removeEventListener('dragenter', dragenter)
containerRef.value.removeEventListener('dragover', dragover)
containerRef.value.removeEventListener('dragleave', dragleave)
containerRef.value.removeEventListener('drop', drop)
}
return{
dragstart,
dragend
}
}
3.處理畫布區域
<div class="editor-container-canvas__content"
style={containerStyles.value}
ref={containerRef}
onMousedown={containerMousedown}>
{
(data.value.blocks.map(block => (
<EditorBlock
class={block.focus ? 'editor-block-focus' : ''}
block={block}
onMousedown={(e) => blockMousedown(e, block)}
></EditorBlock>
)))
}
</div>
元件傳值
當元件被拉倒畫布後
const drop = (e) => {
//先留在這
console.log(e.offsetY)
console.log(e.offsetX)
let blocks = data.value.blocks;//內部已渲染的元件
data.value = {
...data.value, blocks: [
...blocks,
{
top: e.offsetY,
left: e.offsetX,
zIndex: 1,
key: currentComponent.key,
alignCenter: true //鬆手時劇中
}
]
}
currentComponent = null
}
將新元件(拖拽元件)的相關值新增到data.value.blocks中,最後由渲染器進行渲染
(data.value.blocks.map(block => (
<EditorBlock
class={block.focus ? 'editor-block-focus' : ''}
block={block}
onMousedown={(e) => blockMousedown(e, block)}
></EditorBlock>
)))