React中使用.map()时如何在列表行之间添加图标
简便实现行间分隔的方案
不用折腾窗口尺寸计算,直接通过检测元素的垂直位置判断换行,下面是具体实现:
思路
利用DOM元素的offsetTop属性,当某个列表项的垂直位置比前一项高时,说明它是新行的第一个元素,此时在它前面插入分隔组件。同时监听窗口 resize 事件,确保窗口大小变化时重新检测换行位置。
代码实现
import React, { useState, useRef, useLayoutEffect, useCallback } from 'react' import { ListItem } from './ListItem' // 自定义分隔线组件,也可以用原生div替代 const Divider = () => <div style={{ width: '100%', height: 1, backgroundColor: '#ccc', margin: '8px 0' }} /> const REPORTS = [ { id: 1, name: 'first report' }, { id: 2, name: 'second report' }, { id: 3, name: 'third report' }, { id: 4, name: 'fourth report' }, { id: 5, name: 'fifth report' }, { id: 6, name: 'sixth report' }, { id: 7, name: 'Kyles report' }, ] export const ReportsList = () => { const [reports, setReports] = useState(REPORTS) const [renderItems, setRenderItems] = useState([]) const listRef = useRef(null) // 检测换行并生成带分隔符的列表 const updateRenderList = useCallback(() => { if (!listRef.current) return const itemElements = Array.from(listRef.current.children) if (itemElements.length === 0) return const newRenderList = [] let prevTop = itemElements[0].offsetTop // 先添加第一个列表项 newRenderList.push( <ListItem key={reports[0].id} index={0} text={reports[0].name} /> ) // 遍历剩余项,判断是否需要插入分隔符 for (let i = 1; i < reports.length; i++) { const currentTop = itemElements[i].offsetTop if (currentTop > prevTop) { newRenderList.push(<Divider key={`divider-${i}`} />) } newRenderList.push( <ListItem key={reports[i].id} index={i} text={reports[i].name} /> ) prevTop = currentTop } setRenderItems(newRenderList) }, [reports]) // 初始渲染和窗口 resize 时更新列表 useLayoutEffect(() => { updateRenderList() const handleResize = () => { // 防抖处理,避免频繁触发 clearTimeout(window.resizeTimer) window.resizeTimer = setTimeout(updateRenderList, 100) } window.addEventListener('resize', handleResize) return () => window.removeEventListener('resize', handleResize) }, [updateRenderList]) return ( <div ref={listRef} className='boxList'> {/* 初始渲染用原列表,避免空内容 */} {renderItems.length > 0 ? renderItems : reports.map((report, index) => ( <ListItem key={report.id} index={index} text={report.name} /> ))} </div> ) }
补充说明
- 用
useLayoutEffect代替useEffect,确保DOM更新后立刻检测位置,避免获取到不准确的offsetTop值 - 加入防抖处理,窗口 resize 时不会频繁触发更新,提升性能
- 分隔组件可根据需求自定义样式,无需额外依赖
内容的提问来源于stack exchange,提问作者Gabriel
相关产品推荐
相关产品推荐

