容器内选择单一列表并进行高亮切换的实践
大约 2 分钟
容器内选择单一列表并进行高亮切换的实践
基于React和antd技术栈下,对有限容器内列表选择的行进行高亮提示,并且不影响容器内部进行的滚动查看引发的思考,涉及的内容包括overflow熟悉,CSS 类名替换而不是改写style、React Element的复用和性能优化。
前置知识
overflow
overflow 是overflow-x 和overflow-y的简写,用来设定当一块级元素(通常设置了height/max-height)的内容太大而超出范围的时候,元素内容如何加载。
overflow:属性值;
overflow: [overflow-x] [overflow-y];
只设定一个值的话,则同时对x和y轴生效,当其中一方被设置了auto的话,visible的表现也会是auto
其他用途
text-overflow 与 overflow 配合用于文字省略
超出文字隐藏:overflow:hidden; 文字不换行:text-wrap:nowrap;
overflow: hidden 清除浮动
overflow: hidden 解决外边距折叠问题(触发BFC)
分析实践
CSS 类名替换而不是改写style
并不适用于虚拟列表
demo 演示
设置容器、列表样式以及选中行的样式:
.main {
background: grey;
margin: auto;
width: 50vw;
height: 400px;
overflow: auto;
}
.list {
width: 100vw;
height: 100vw;
}
.active {
background: aqua;
}
// App.jsx
import React, {useState} from 'react';
import './App.css';
import {List} from "antd";
const data = [
'Racing car sprays burning fuel into crowd.',
'Japanese princess to wed commoner.',
'Australian walks 100km after outback crash.',
'Man charged over missing wedding girl.',
'Los Angeles battles huge wildfires.',
];
function App() {
const [activeIndex, setActiveIndex] = useState(-1)
return (
<div className={"main"}>
<div className={"list"}>
<List
size="small"
bordered
dataSource={data}
renderItem={(item, index) => (
<List.Item
className={index === activeIndex ? "active" : ""}
onClick={() => {
setActiveIndex(index)
}}>{item}</List.Item>
)}
/>
</div>
</div>
);
}
export default App;
显示效果
通过设置外部容器固定宽高,overflow: auto已经生效,生成滚动条
外部内容被隐藏遮住
当点击的时候,改变的是仅受影响的两行的类名
此修改方法通过只修改类名而不是style属性,更有利于后期维护和修改选中的样式,我们只需对.active
进行修改即可。如果是写成style形式,就很冗余了,也不好扩展。
style={index === activeIndex ? {backgroundColor: '#f5f5f5'} : {}}
思考问题
数据量大了怎么办?目前修改相当于整个App都被重新执行了渲染,行数多了有明显卡顿,甚至没有反应,而且生成的时候这行相当于进行多了次比较:
className={activeIndex === index ? "active" : ""}
Mark一下,待思考解决办法:
只对选中行进行重绘
通过标记之前选中的节点,在下次选中的时候进行重写className
let preClickElement = null
const handleClick = useCallback((e) => {
const target = e.currentTarget
target.className = 'ant-list-item active';
preClickElement && (preClickElement.className = 'ant-list-item')
preClickElement = target;
}, [])
demo
{
data.map((item, index) => {
return <List.Item
key={index}
onClick={handleClick}>{item}</List.Item>
})
}
如果用虚拟列表的话,如何实现这个效果?
Mark,重写一个虚拟列表demo后尝试