本文仅为总结技术点,阅读需要中高的前端基础、和一定的低代码基础
拖拽
采用react-dnd
进行拖拽
把画布stage
设置为需要的样式(demo
固定为375设计稿),并添加drop
用于放置拖拽过来的物料:
const Stage: FC = () => {
const components = useComponentSchema((s) => s.components)
const renderNodes = Array.isArray(components)
? components.map((c) => render(c))
: render(components)
// 添加drop逻辑
const [{ canDrop }, drop] = useDrop({
accept: COMPONENT_TYPES,
collect: (monitor) => ({
canDrop: monitor.canDrop()
})
})
return (
<div className="flex-1 bg-[#edeff3] h-full flex items-center justify-center p-10">
<div
className={C('w-[375px] h-full bg-white', {
'border border-dashed border-[#3333ff]': canDrop
})}
ref={drop}
>
{renderNodes}
</div>
</div>
)
}
其中useComponentSchema
采用zustand
做schema
的状态管理:
type State = {
components: AllComponentType[]
}
type Action = {
addComponents: (component: AllComponentType) => void
}
const useComponentSchema = create<State & Action>((set) => ({
components: [],
addComponents: (component: AllComponentType) => {
set((state) => ({
components: [...state.components, component]
}))
}
}))
但是最好还是封装一个componentHydrate
,用来处理整个component
的add delete upgrade
:
const addComponents = (
type: AllComponentType['type'],
customProps?: AllComponentType['props']
) => {
const { addComponents } = useComponentSchema.getState()
// 通过getDefaultComponentSchema获取某个type的组件的默认配置
const schema = getDefaultComponentSchema(
type,
customProps
) as AllComponentType
if (!schema) {
return
}
addComponents(schema)
}
实现容器拖拽
同理,实现一个容器物料,比如div,接收被拖拽的物料,则需要实现容器物料能够被放置。在前面我们渲染原生标签用的是React.createElement
,则现在需要自己写物料组件,返回JSX。
// 实现物料 div容器
type Props = Omit<BoxComponentProps['props'], 'children'> & { 'data-id': ID }
const Div: FC<PropsWithChildren<Props>> = (props) => {
const { children, ...divProps } = props
const [{ canDrop }, drop] = useDrop({
accept: COMPONENT_TYPES,
collect: (monitor) => ({
canDrop: monitor.canDrop()
}),
drop(): DROP_RESULT_TYPE {
console.log('drop div')
return {
type: NATIVE_COMPONENT_ENUM.BOX,
id: divProps['data-id']
}
}
})
return (
<div
ref={drop}
{...divProps}
className={C('border border-solid min-h-[50px] ', {
'border-[#3333ff] border-dashed': canDrop
})}
>
{children}
</div>
)
}
export default Div
但是多个drop
层叠的时候,需要确定好drag到哪一个,这是一个复杂的问题(在下面),目前就先放在schema最深的能接受这个drag type
的drop
上。
几个问题:
- 怎么确定被拖拽的物料是要放在哪个已经在画布上的容器?
- 怎么勾画出能够放置被拖拽的物料位置提示?
- 是否能写一个通用
dragwrapper
和通用dropwrapper
分别处理新增和编辑的情况