Puck 如何用 slot 字段搭建多列布局?

发布时间:2026/9/15 17:06:31
Puck 如何用 slot 字段搭建多列布局? Puck 如何用 slot 字段搭建多列布局【免费下载链接】puckThe visual editor for React.项目地址: https://gitcode.com/GitHub_Trending/puc/puckPuck 的可视化编辑器本身按垂直方向排列组件但官方文档明确说明Puck 通过slot字段支持任意 CSS 布局下的嵌套与多列布局Multi-column Layouts。本文的目标是在你自己的 Puck 配置里搭出一个可拖拽填充的多列布局先用 slot 定义一个可拖入组件的区域再用两个或多个 slot 字段或 CSS grid/flex 把它们排成多列最后按需移除 Puck 的包裹元素、限制可拖入的组件。前提是你已经有一个能渲染 Puck 编辑器的项目。按 Getting Started 的说法安装puckeditor/corenpm i puckeditor/core --save或用npx create-puck-app my-app生成应用然后这样挂载编辑器import { Puck } from puckeditor/core; const config { /* 本文下方各节的 components 配置 */ }; const initialData {}; const save (data) {}; // 保存到数据库 export function Editor() { return Puck config{config} data{initialData} onPublish{save} /; }发布后的页面用Render config{config} data{data} /渲染。下面的所有配置都写进config.components。slot 字段如何把数据变成多列区域先理解 slot 字段的工作方式后面所有写法都建立在它上面slot 字段产出一个ComponentData数组即在 slot 里拖入的每个组件都存为一条{ type, props }记录这个数组在传给组件的render()之前会被转换成一个 render function你在render里把它当组件用如Content /并可给它传 propsslot 字段在右侧表单区不渲染任何 UI内容只能通过拖放编辑见 Slot 字段 API。最简用法是给组件加一个contentslot然后在render里解构出来直接渲染const config { components: { Example: { fields: { content: { type: slot, }, }, render: ({ content: Content }) { return Content /; }, }, Card: { render: () divHello, world/div, }, }, };此时Example内部就出现了一个可拖入组件的区域。如果项目使用 TypeScript按 slot 文档的要求使用Slot类型render prop 才能被正确转换import { Slot } from puckeditor/core; type Props { Example: { content: Slot; // Converted from the ComponentData[] type into a render function }; };字段参数方面slot 只有type: slot是必填的可选参数还有allow和disallow后文单独讲。固定两列布局为每一列定义一个 slot固定列数比如左列放导航、右列放正文的做法是组合多个 slot 字段再用 CSS grid 定位每一列const config { components: { Example: { fields: { leftColumn: { type: slot, }, rightColumn: { type: slot, }, }, render: ({ leftColumn: LeftColumn, rightColumn: RightColumn }) { return ( div style{{ display: grid, gridTemplateColumns: 1fr 1fr, gap: 16 }} LeftColumn / RightColumn / /div ); }, }, Card: { render: ({ text }) div{text}/div, }, }, };gridTemplateColumns: 1fr 1fr是均分两列想要三列或不等宽列改这个值即可。注意文档说明slot取代 DropZone 后内的组件默认沿垂直block轴排列即每一列内部是纵向堆叠的多列结构由你自己的 grid 容器决定。仓库自带的 demo 里有更完整的列布局实现可以参考Grid 块用一个numColumnsnumber 字段min: 1, max: 12加一个itemsslot通过gridTemplateColumns: repeat(${numColumns}, 1fr)让列数可在编辑器里调节Flex 块则是用flexDirection、justifyContent、gap等字段控制一个 flex 容器内的 slot。流式布局给 slot 传 style 或 className列数不固定、内容自由流动时不改组件结构直接给 slot 的 render function 传style或classNamepropsconst config { components: { Example: { fields: { content: { type: slot, }, }, render: ({ content: Content }) ( Content style{{ // Use CSS grid in this slot display: grid, gridTemplateColumns: 2fr 1fr, gap: 16, }} / ), }, Card: { render: ({ text }) div{text}/div, }, }, };文档明确 Puck 对所有display值包括grid和flex都支持拖放。slot render function 支持的 props 有allow、as、className、collisionAxis、disallow、minEmptyHeight、ref、style。其中两个与多列布局直接相关collisionAxis控制拖放时的碰撞检测轴取值x、y、dynamic。不设置时按父级 CSS 布局取默认值grid 为dynamicflexrow和 inline/inline-block 为x其余为y。多列 grid 布局用默认值即可minEmptyHeight是 slot 为空时的最小高度默认128px编辑空 slot 时可以调整它让放置区域更容易点中。需要 flex-grow、grid-column 等规则时移除 Puck 包裹元素这里有一个多列布局特有的坑默认情况下 Puck 会把每个组件包在一个div里。如果你想在布局里对子组件直接用flex-grow、grid-column、grid-row这类 CSS 规则包裹元素会挡住样式必须去掉。文档给出的方案是给组件配置inline: trueComponentConfig 的 inline 参数。同时有一个强制要求使用inline时必须把puck.dragRef传给某个元素的refprop告诉 Puck 哪个元素可拖拽否则拖放失效。const config { components: { Example: { fields: { content: { type: slot, }, }, render: ({ content: Content }) ( Content style{{ display: grid, gridTemplateColumns: 1fr 1fr 1fr 1fr, gridTemplateRows: 1fr 1fr 1fr 1fr, gap: 16, }} / ), }, Card: { inline: true, // Enable inline mode, removing the Puck wrapper render: ({ text, spanCol, spanRow, puck }) ( div ref{puck.dragRef} // Let Puck know this element is draggable style{{ gridColumn: span ${spanCol}, gridRow: span ${spanRow}, }} {text} /div ), }, }, };这个例子里Card跨几列、跨几行由它自己的spanCol、spanRowprops 决定配合对应字段即可在编辑器里调节组件直接作为 slot 容器的子孙节点参与 grid 布局。限制哪些组件可以拖入某一列多列布局中常见需求是左列只放卡片、不允许放导航。在 slot 字段上用allow/disallow参数限制const config { components: { Example: { fields: { content: { type: slot, allow: [Card], }, }, render: ({ content: Content }) { return Content /; }, }, }, };disallow则是排除法。两者可以结合 categories 复用已有的组件分组const config { categories: { typography: { components: [Card], }, }, components: { Example: { fields: { content: { type: slot, allow: categories.typography.components, }, }, render: ({ content: Content }) { return Content /; }, }, }, };也可以把allow/disallow作为 props 传给 slot 的 render function但 slot 文档特别警告大纲outline中的拖放不遵守这两个 render props要处处生效应优先使用字段参数。让新组件插入时带默认列内容配合defaultProps可以给 slot 预填内容值是一个ComponentData数组const config { components: { Example: { fields: { content: { type: slot, }, }, defaultProps: { content: [ { type: Card, props: { text: Pre-populated, }, }, ], }, render: ({ content: Content }) Content /, }, Card: { render: ({ text }) div{text}/div, }, }, };这样每次从侧栏插入Example时slot 里已经有一条Card多列布局不会出现空列。验证数据结构和编辑器表现完成后按下面两点核对两者都来自文档对 slot 数据模型的描述编辑器内把组件拖进 slot 区域slot 会以style/gridTemplateColumns定义的列结构渲染slot 为空时保留minEmptyHeight指定的最小高度默认128px。数据结构slot 的数据是内联存储的——子组件以ComponentData数组的形式存在父组件的props里而不是旧的独立zones对象。保存一条包含 Grid 布局的数据后形状如下取自 DropZones to Slots 迁移文档的示例{ content: [ { type: Grid, props: { id: Grid-12345, items: [ { type: HeadingBlock, props: { id: Heading-12345, title: Hello, world } } ] } } ] }如果检查发现数据仍挂在zones下说明用的是旧的 DropZone 数据模型见下节迁移。从旧 DropZone 数据迁移slot 取代了DropZone组件后者即将被弃用移除。新建的 slot 不需要额外操作如果已有 DropZone 数据用migrate()辅助函数转换它会迁移zones里与同名 slot 对应的内容import { migrate } from puckeditor/core; import config from puck.config.tsx; const newData migrate(legacyData, config);如果旧数据里存在循环渲染 DropZone 产生的动态 zone 名迁移文档提供了migrateDynamicZonesForComponent选项按组件自定义映射例如把每个 zone 转成一个columnprop。限制与边界slot 字段本身不产生表单 UIslot 内容只能在画布或大纲里拖放编辑传allow/disallow给 slot render function 只在画布拖放中生效大纲拖放不遵守全局限制请用字段参数inline: true与puck.dragRef是绑定关系缺dragRef拖放会失效每条ComponentData的props必须有唯一idPuck 自动生成子组件记录同样遵守 ComponentData 的结构。进一步的 API 细节见 slot 字段完整文档和 Multi-column Layouts 指南。【免费下载链接】puckThe visual editor for React.项目地址: https://gitcode.com/GitHub_Trending/puc/puck创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考