前端组件库 ——React Aria 知识点大全(三)

简介: 教程来源 http://xcfsr.cn React Aria 提供集合组件(列表框、表格、虚拟滚动)与拖拽排序能力,均深度集成无障碍支持:`useListBox`/`useTable`确保键盘导航与ARIA语义,`useVirtualizer`优化大数据渲染性能,`useDrag`/`useDrop`实现可访问的拖放交互。

四、集合组件

React Aria 提供了一套强大的集合组件系统,用于处理列表、表格、树等结构化数据。

4.1 useListBox - 列表框
useListBox 用于创建可访问的列表框,支持单选/多选、键盘导航等。通常与 useListBoxSection 和 useOption 结合使用。

import { useListBox, useOption } from 'react-aria';
import { useListState } from 'react-stately';

function ListBox(props) {
    let state = useListState(props);
    let ref = useRef(null);
    let { listBoxProps } = useListBox(props, state, ref);

    return (
        <ul {...listBoxProps} ref={ref} style={
  {
            margin: 0,
            padding: '8px 0',
            listStyle: 'none',
            border: '1px solid #ccc',
            borderRadius: '4px',
            background: 'white',
            width: '200px'
        }}>
            {[...state.collection].map(item => (
                <Option key={item.key} item={item} state={state} />
            ))}
        </ul>
    );
}

function Option({ item, state }) {
    let ref = useRef(null);
    let { optionProps, isSelected, isFocused } = useOption({ key: item.key }, state, ref);

    return (
        <li {...optionProps} ref={ref} style={
  {
            padding: '8px 12px',
            background: isSelected ? '#007bff' : isFocused ? '#f0f0f0' : 'transparent',
            color: isSelected ? 'white' : 'black',
            cursor: 'pointer'
        }}>
            {item.rendered}
        </li>
    );
}

4.2 useTable - 表格组件
http://htnus.cn
useTable 系列 Hooks(useTable、useTableColumnHeader、useTableRow、useTableCell)用于创建可访问的数据表格,支持列排序、选择、键盘导航等高级功能。

import { useTable, useTableColumnHeader, useTableRow, useTableCell } from 'react-aria';
import { useTableState } from 'react-stately';

function Table(props) {
    let state = useTableState(props);
    let ref = useRef(null);
    let { gridProps } = useTable(props, state, ref);

    return (
        <div style={
  { overflow: 'auto' }}>
            <table {...gridProps} ref={ref} style={
  { borderCollapse: 'collapse', width: '100%' }}>
                <thead>
                    <tr>
                        {[...state.collection.headerRows].map(headerRow => (
                            <TableRow key={headerRow.key} item={headerRow} state={state} isHeader />
                        ))}
                    </tr>
                </thead>
                <tbody>
                    {[...state.collection.body].map(row => (
                        <TableRow key={row.key} item={row} state={state} />
                    ))}
                </tbody>
            </table>
        </div>
    );
}

function TableRow({ item, state, isHeader }) {
    let ref = useRef(null);
    let { rowProps } = useTableRow({ node: item }, state, ref);

    return (
        <tr {...rowProps} ref={ref}>
            {[...item.childNodes].map(column => (
                isHeader
                    ? <TableHeaderColumn key={column.key} column={column} state={state} />
                    : <TableCell key={column.key} column={column} state={state} />
            ))}
        </tr>
    );
}

function TableHeaderColumn({ column, state }) {
    let ref = useRef(null);
    let { columnHeaderProps } = useTableColumnHeader({ node: column }, state, ref);

    return (
        <th {...columnHeaderProps} ref={ref} style={
  { borderBottom: '2px solid #ccc', padding: '12px', textAlign: 'left' }}>
            {column.rendered}
        </th>
    );
}

function TableCell({ column, state }) {
    let ref = useRef(null);
    let { gridCellProps } = useTableCell({ node: column }, state, ref);

    return (
        <td {...gridCellProps} ref={ref} style={
  { borderBottom: '1px solid #eee', padding: '12px' }}>
            {column.rendered}
        </td>
    );
}

4.3 useVirtualizer - 虚拟滚动
在处理大量数据时,useVirtualizer 可以显著提升性能,只渲染视口内的内容。

import { useTable, useVirtualizer } from 'react-aria';
import { useTableState } from 'react-stately';

function VirtualTable(props) {
    let state = useTableState(props);
    let ref = useRef(null);
    let { gridProps } = useTable(props, state, ref);

    // 计算行高和可见范围
    let rowHeight = 48;
    let rows = [...state.collection.body];
    let totalHeight = rows.length * rowHeight;

    // 根据滚动位置计算可见行
    let isScrolling = useVirtualizer();
    let [scrollTop, setScrollTop] = useState(0);
    let startIndex = Math.floor(scrollTop / rowHeight);
    let endIndex = Math.min(startIndex + Math.ceil(ref.current?.clientHeight / rowHeight) + 5, rows.length);
    let visibleRows = rows.slice(startIndex, endIndex);
    let offsetY = startIndex * rowHeight;

    const handleScroll = (e) => {
        setScrollTop(e.currentTarget.scrollTop);
    };

    return (
        <div ref={ref} onScroll={handleScroll} style={
  { height: 400, overflow: 'auto' }}>
            <div {...gridProps} style={
  { position: 'relative', height: totalHeight }}>
                <div style={
  { position: 'absolute', top: offsetY, left: 0, right: 0 }}>
                    <tr>
                        {visibleRows.map(row => (
                            <TableRow key={row.key} item={row} state={state} />
                        ))}
                    </tbody>
                </div>
            </div>
        </div>
    );
}

五、拖拽与排序

React Aria 提供了完整的拖拽支持,包括拖拽源、放置目标、拖拽预览等。useDrag 和 useDrop 是核心的基础 Hooks。

5.1 useDrag - 拖拽源

import { useDrag } from 'react-aria';

function DraggableItem({ item }) {
    let ref = useRef(null);
    let { dragProps, isDragging } = useDrag({
        getItems: () => [{ 'text/plain': item.name }],
        onDragStart: () => console.log('拖拽开始'),
        onDragEnd: () => console.log('拖拽结束')
    });

    return (
        <div ref={ref} {...dragProps} style={
  {
            padding: '8px 12px',
            margin: '4px',
            background: isDragging ? '#e0e0e0' : '#f5f5f5',
            border: '1px solid #ccc',
            borderRadius: '4px',
            cursor: 'grab',
            opacity: isDragging ? 0.5 : 1
        }}>
            {item.name}
        </div>
    );
}

5.2 useDrop - 放置目标

import { useDrop } from 'react-aria';

function DropZone({ onDrop }) {
    let ref = useRef(null);
    let { dropProps, isDropTarget } = useDrop({
        onDrop: async (e) => {
            let items = await Promise.all(
                e.items
                    .filter(item => item.kind === 'string' && item.types.has('text/plain'))
                    .map(item => item.getText('text/plain'))
            );
            onDrop(items);
        }
    });

    return (
        <div ref={ref} {...dropProps} style={
  {
            padding: '100px',
            border: `2px dashed ${isDropTarget ? '#007bff' : '#ccc'}`,
            borderRadius: '8px',
            textAlign: 'center',
            background: isDropTarget ? '#f0f8ff' : 'white'
        }}>
            拖拽文件或元素到这里
        </div>
    );
}
相关文章
|
关系型数据库 MySQL 网络安全
关于对连接数据库时出现1130-host “**” is not allowed to connect to this MySql/mariadb server
关于对连接数据库时出现1130-host “**” is not allowed to connect to this MySql/mariadb server
802 0
|
前端开发 JavaScript 开发工具
从零开始:构建、打包并上传个人前端组件库至私有npm仓库的完整指南
从零开始:构建、打包并上传个人前端组件库至私有npm仓库的完整指南
3201 0
|
JSON JavaScript API
【Vue3 易混淆概念点一】ref、toRef、toRefs、reactive 异同点
【Vue3 易混淆概念点一】ref、toRef、toRefs、reactive 异同点
536 0
|
JavaScript
Vue3--ref 和 $refs 的使用
Vue3--ref 和 $refs 的使用
1571 0
|
JavaScript 前端开发 容器
从 0 到 1 实现 React 系列 —— JSX 和 Virtual DOM
作者的博客 看源码一个痛处是会陷进理不顺主干的困局中,本系列文章在实现一个 (x)react 的同时理顺 React 框架的主干内容(JSX/虚拟DOM/...) 环境准备 项目打包工具选择了 parcel,使用其可以快速地进入项目开发的状态。
1577 0
|
4天前
|
缓存 测试技术 API
Qwen 3.7 Plus 与 Max 实测:性价比与多模态能力差异解析(2026)
2026 年 6 月 1 日,阿里悄无声息地发布了 Qwen 3.7 Plus,距 Qwen 3.7 Max 上线刚好 11 天。同样的 1M 上下文,同样的 35 小时自治上限。但价格才是头条:Plus 是 0.40/M输入,Max是 2.50/M——便宜约 6 倍——并且还能看图、看视频。Vision Arena 上 Plus 已经排到 #16。所以这周真正值得讨论的问题不是”要不要为视觉能力买单”,而是”Max 凭什么用 6 倍价格换来 2 个百分点的 benchmark 领先”。
|
5天前
|
人工智能 自然语言处理 文字识别
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
Qwen3.7-Max是阿里云百炼面向智能体时代推出的新一代旗舰模型,对标GPT-5.5、Claude Opus 4.7等闭源旗舰。该模型支持百万级token上下文窗口,具备顶级推理能力、多模态搜索与视觉理解增强、流式输出低延迟响应等核心优势,覆盖编程、办公、长周期自主执行等复杂场景。同时支持OpenAI接口兼容,便于系统快速迁移。用户可通过Token Plan团队或节省计划等订阅方式灵活调用,适合企业级高要求场景使用。
8619 37
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
|
5天前
|
JavaScript 定位技术 API
CodeGraph 爆火:编程 Agent 需要的不是更多上下文,而是一张提前画好的代码地图
CodeGraph 是一款爆火的本地代码智能工具,通过 tree-sitter 解析 AST 构建结构化知识图谱(存于 SQLite),为编程 Agent 提前生成“代码地图”。它显著降低 Agent 在中大型项目中的探索成本——实测工具调用减少71%、Token 降57%、速度提升46%,支持19+语言及主流框架路由识别,完全离线、无需 API Key。
649 4
CodeGraph 爆火:编程 Agent 需要的不是更多上下文,而是一张提前画好的代码地图
|
5天前
|
人工智能 运维 JavaScript
阿里云Qoder CN(原通义灵码)全解析 产品形态、版本划分与技术适配说明
在AI辅助开发与智能办公工具持续普及的当下,阿里云旗下原通义灵码正式更名为Qoder CN,同时延伸出QoderWork CN、Qoder CN CLI、Qoder CN Mobile等多款配套产品,形成覆盖代码开发、日常办公、终端交互、移动端使用的完整工具矩阵。Qoder CN核心定位为AI智能编码助手,深度适配主流代码编辑器、集成开发环境以及终端场景;QoderWork CN则偏向桌面端综合办公辅助,二者面向不同使用场景,划分了多个版本档位,搭配差异化资源配额、功能权限与计费规则,同时兼容多款主流大模型。
651 5
|
5天前
|
数据采集 人工智能 前端开发
让 Coding Agent 从黑盒到透明:阿里云 Agent 观测审计数据采集实践
AI Agent 规模化落地带来执行黑盒、行为难追溯、成本难度量三大难题。阿里云基于 OTel 标准,面向 Coding Agent、个人通用助理和框架型 Agent,推出 LoongSuite Pilot、插件及探针等无侵入采集方案,让 Agent 实现可看见、可分析、可审计、可治理。
724 149