react-window 固定行 sticky
image.png

  1. import React, { createContext, forwardRef } from "react";
  2. import { FixedSizeList as List } from "react-window";
  3. const Context = createContext();
  4. const ItemWrapper = ({ data, index, style }) => {
  5. const { ItemRenderer, stickyIndices } = data;
  6. // 过滤掉固定的行
  7. if (stickyIndices && stickyIndices.includes(index)) {
  8. return null;
  9. }
  10. return <ItemRenderer index={index} style={style} />;
  11. };
  12. // 滚动的行
  13. const Row = ({ index, style }) => {
  14. return (
  15. <div className="row" style={style}>
  16. Row {index}
  17. </div>
  18. )
  19. };
  20. // 固定的行
  21. const StickyRow = ({ index, style }) => (
  22. <div className="sticky" style={style}>
  23. Sticky Row {index}
  24. </div>
  25. );
  26. const innerElementType = forwardRef(({ children, ...rest }, ref) => {
  27. return (
  28. <Context.Consumer>
  29. {({ stickyIndices }) => (
  30. <div ref={ref} {...rest}>
  31. {stickyIndices.map(index => (
  32. <StickyRow
  33. index={index}
  34. key={index}
  35. style={{ top: index * 35, left: 0, width: "100%", height: 35 }}
  36. />
  37. ))}
  38. {children}
  39. </div>
  40. )}
  41. </Context.Consumer>
  42. )
  43. });
  44. function StickyList(props) {
  45. const { children, stickyIndices, ...rest } = props;
  46. return (
  47. <Context.Provider value={{ ItemRenderer: children, stickyIndices }}>
  48. <List itemData={{ ItemRenderer: children, stickyIndices }} {...rest}>
  49. {ItemWrapper}
  50. </List>
  51. </Context.Provider>
  52. );
  53. }
  54. function App() {
  55. return (
  56. <StickyList
  57. height={150}
  58. innerElementType={innerElementType}
  59. itemCount={1000}
  60. itemSize={35}
  61. stickyIndices={[0, 1]} // 那几列固定
  62. width={300}
  63. >
  64. {Row}
  65. </StickyList>
  66. )
  67. }
  68. export default App;

less

  1. .sticky {
  2. position: sticky !important;
  3. position: -webkit-sticky !important;
  4. z-index: 2;
  5. }
  6. .row, .sticky {
  7. display: flex;
  8. align-items: center;
  9. background-color: white;
  10. border-bottom: 1px solid #eee;
  11. box-sizing: border-box;
  12. }