如何不使用React还原react-grid-layout布局 实现跨框架复用
原生复现react-grid-layout布局效果方案
react-grid-layout的核心实现依赖CSS Grid布局+原生事件监听,完全可以脱离React框架实现,跨框架复用时只需要共享布局状态数组即可。
核心实现步骤
- 布局层:用CSS Grid作为基础布局方案,提前定义全局统一的列数、行高、网格间隙参数,所有卡片的位置、宽高都和网格线严格对齐,和react-grid-layout的对齐逻辑完全一致
- 交互层:用原生
mousedown/mousemove/mouseup事件组合实现拖拽、resize功能,不需要引入任何第三方依赖:- 拖拽触发时记录当前卡片的初始位置、鼠标初始坐标,全局绑定移动、抬起事件
- 鼠标移动时实时计算偏移量,换算为网格单位的坐标增量,更新卡片位置
- 鼠标抬起时解绑全局事件,更新全局布局状态
- 碰撞处理:卡片位置、尺寸变更时遍历所有卡片,检测是否出现重叠,按照“下方元素自动下压”的逻辑调整其他卡片位置,和react-grid-layout的默认压缩行为对齐
- 状态层:将所有卡片的id、x坐标、y坐标、宽度w、高度h存储为纯JSON数组,该数组和框架完全无关,可以在React、Angular、Vue等任意框架中直接读取渲染
最简实现代码示例
HTML结构
<div class="grid-container"> <div class="grid-item" data-id="item1" data-x="0" data-y="0" data-w="2" data-h="2"> 卡片1 <div class="resize-handle"></div> </div> <div class="grid-item" data-id="item2" data-x="2" data-y="0" data-w="1" data-h="1"> 卡片2 <div class="resize-handle"></div> </div> </div>
CSS样式
/* 网格容器基础样式 */ .grid-container { display: grid; grid-template-columns: repeat(12, 1fr); /* 12列网格,可自定义列数 */ grid-auto-rows: 80px; /* 单行高度,可自定义 */ gap: 16px; /* 网格间隙,可自定义 */ padding: 16px; } /* 网格卡片样式 */ .grid-item { position: relative; background: #ffffff; border: 1px solid #e2e8f0; border-radius: 6px; padding: 12px; cursor: move; user-select: none; } /* resize触发柄样式 */ .resize-handle { position: absolute; right: 6px; bottom: 6px; width: 14px; height: 14px; background: #3b82f6; border-radius: 2px; cursor: se-resize; }
核心JS逻辑
// 全局配置,和CSS参数保持一致即可 const GRID_CONFIG = { colCount: 12, rowHeight: 80, gap: 16 } const container = document.querySelector('.grid-container') // 全局布局状态,纯JSON数组,可跨框架复用 let layout = Array.from(document.querySelectorAll('.grid-item')).map(el => ({ id: el.dataset.id, x: parseInt(el.dataset.x), y: parseInt(el.dataset.y), w: parseInt(el.dataset.w), h: parseInt(el.dataset.h) })) // 布局渲染函数,根据layout数组更新所有卡片的网格属性 function renderLayout() { layout.forEach(item => { const el = document.querySelector(`[data-id="${item.id}"]`) el.style.gridColumnStart = item.x + 1 el.style.gridColumnEnd = item.x + item.w + 1 el.style.gridRowStart = item.y + 1 el.style.gridRowEnd = item.y + item.h + 1 }) } // 初始化渲染布局 renderLayout() // 后续可补充拖拽、resize、碰撞检测的事件逻辑,均为原生JS实现,无框架依赖
跨框架适配方法
在Angular等其他框架中使用时,只需要把上述layout数组存储为框架的响应式状态,渲染时将对应x/y/w/h的值绑定到元素的grid-column/grid-row相关属性上即可,拖拽、resize的原生事件逻辑不需要修改,直接引入即可生效。
内容的提问来源于stack exchange,提问作者Albert Gao
相关产品推荐
相关产品推荐

