12.12【java exp4】react table全局搜索tailwindcss 布局 (Layout) css美化 3. (rowId: number

react table

  1. 创建一个下拉菜单,允许用户选择要搜索的列。
  2. 创建一个输入框,用于输入搜索关键词。
  3. 根据用户的选择,动态地应用过滤器到指定的列

全局搜索

javascript 复制代码
import React from 'react';
import { useTable, useFilters, useGlobalFilter, useSortBy, usePagination } from 'react-table';

// 自定义过滤组件
function ColumnFilter({ column }) {
  const { filterValue, setFilter } = column;
  return (
    <input
      value={filterValue || ''}
      onChange={(e) => setFilter(e.target.value)}
      placeholder={`Search ${column.id}`}
      style={{ marginBottom: '0.5rem' }}
    />
  );
}

const data = [
  { id: 1, name: 'Alice', age: 24, email: '[email protected]' },
  { id: 2, name: 'Bob', age: 30, email: '[email protected]' },
  { id: 3, name: 'Charlie', age: 28, email: '[email protected]' },
];

const columns = React.useMemo(
  () => [
    {
      Header: 'ID',
      accessor: 'id',
      Filter: ColumnFilter, // 为 ID 列添加过滤器
    },
    {
      Header: 'Name',
      accessor: 'name',
      Filter: ColumnFilter, // 为 Name 列添加过滤器
    },
    {
      Header: 'Age',
      accessor: 'age',
      Filter: ColumnFilter, // 为 Age 列添加过滤器
    },
    {
      Header: 'Email',
      accessor: 'email',
      Filter: ColumnFilter, // 为 Email 列添加过滤器
    },
  ],
  []
);

const DataTable = () => {
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    state: { globalFilter },
    setGlobalFilter,
  } = useTable(
    {
      columns,
      data,
      defaultColumn: { Filter: ColumnFilter }, // 为所有列添加默认过滤器
    },
    useFilters, // 启用列过滤
    useGlobalFilter, // 启用全局过滤
    useSortBy, // 启用排序
    usePagination // 启用分页
  );

  // 全局搜索输入框
  const [searchInput, setSearchInput] = React.useState('');

  const handleSearchChange = (e) => {
    const value = e.target.value || '';
    setSearchInput(value);
    setGlobalFilter(value);
  };

  return (
    <div>
      {/* 全局搜索栏 */}
      <div>
        <input
          value={searchInput}
          onChange={handleSearchChange}
          placeholder="Search all columns..."
          style={{ marginBottom: '1rem' }}
        />
      </div>

      {/* 表格 */}
      <table {...getTableProps()} style={{ border: 'solid 1px blue' }}>
        <thead>
          {headerGroups.map((headerGroup) => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map((column) => (
                <th {...column.getHeaderProps(column.getSortByToggleProps())}>
                  {column.render('Header')}
                  {/* 显示排序图标 */}
                  <span>
                    {column.isSorted ? (column.isSortedDesc ? ' 🔽' : ' 🔼') : ''}
                  </span>
                  {/* 渲染列过滤器 */}
                  <div>{column.canFilter ? column.render('Filter') : null}</div>
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {rows.map((row) => {
            prepareRow(row);
            return (
              <tr {...row.getRowProps()}>
                {row.cells.map((cell) => (
                  <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
                ))}
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
};

export default DataTable;

tailwindcss

className 是 React 中用于指定 CSS 类名的一个属性,它并不是 Tailwind CSS 特有的,而是 React 生态系统中的一个标准属性。Tailwind CSS 是一个实用优先的 CSS 框架,可以帮助你快速构建现代化的用户界面,但它并不会改变 className 属性的本质

  1. 引入 Tailwind 样式 : 在你的项目的入口 CSS 文件(通常是 src/index.css)中添加以下内容:

    复制代码
    @tailwind base;
    @tailwind components;
    @tailwind utilities;

Tailwind CSS 是一个高度可定制的、低级别的 CSS 框架,它提供了一套实用工具类(utility-first),而不是预定义的组件样式。与传统的 CSS 框架(如 Bootstrap)不同,Tailwind 不提供现成的按钮、卡片等组件样式,而是通过组合简单的 CSS 类来构建自定义的设计。这使得你可以完全控制设计的每个细节,同时保持代码的简洁和一致性

@tailwind base:

这个指令会引入 Tailwind CSS 的基础样式,包括归一化样式(Normalize CSS)和一些基本的 HTML 元素样式。

例如,它会重置浏览器的默认样式,确保不同浏览器之间的样式一致性。

@tailwind components:

这个指令会引入 Tailwind CSS 的组件样式。

组件样式通常用于定义一些常见的 UI 组件,如按钮、表单元素等。

你可以在这里添加自己的组件样式,或者使用 Tailwind CSS 提供的默认样式。

@tailwind utilities:

这个指令会引入 Tailwind CSS 的实用工具类(Utility Classes)。

实用工具类是一些预定义的 CSS 类,用于快速调整元素的样式,如 text-center、bg-blue-500 等。

这些类可以在 HTML 中直接使用,无需编写额外的 CSS 代码。

  • Tailwind CSS 提供了大量的低级别的、原子化的类名,每个类名对应一个特定的样式属性。
  • 这些类名可以在 HTML 或 JSX 中直接使用,而不需要编写额外的 CSS 文件
  • 由于类名是预先定义好的,开发人员可以立即看到样式的变化,无需来回切换文件进行调试。
  • 这提高了开发效率,减少了上下文切换的时间。
布局 (Layout)
  • Flexbox 和 Grid

整体布局:

使用 p-4 为整个组件添加内边距。

使用 flex 和 items-center 使搜索栏中的元素在同一行对齐。

选择列和搜索输入框:

使用 mr-2 添加右侧外边距。

使用 p-2 添加内边距。

使用 border 和 rounded 添加边框和圆角。

表格:

使用 w-full 使表格宽度占满父容器。

使用 border 和 border-gray-300 添加边框。

使用 bg-gray-100 为表头背景添加浅灰色。

使用 p-2 和 text-left 为表头单元格添加内边距和左对齐。

使用 border-b 和 border-gray-300 为表头和表格行添加底部边框。

分页控制:

使用 mt-4 为分页控件添加顶部外边距。

使用 flex 和 justify-between 使分页按钮和页面信息分别位于两端。

使用 px-2 和 py-1 为按钮添加水平和垂直内边距。

使用 mr-2 为按钮之间添加右侧外边距。

使用 bg-blue-500 和 text-white 为按钮添加蓝色背景和白色文字。

使用 rounded 为按钮添加圆角。

使用 disabled:bg-gray-300 为禁用状态的按钮添加浅灰色背景。

使用 ml-2 为输入框和选择框添加左侧外边距

css美化

如果你导入了多个 CSS 文件,并且这些文件中有重叠的样式规则,CSS 的层叠机制(Cascading)和优先级(Specificity)将决定最终应用的样式。

CSS 层叠机制决定了当多个规则应用于同一个元素时,哪个规则会生效。

规则的优先级顺序如下:

内联样式(Inline styles)

ID 选择器(ID selectors)

类选择器、属性选择器和伪类(Class selectors, attribute selectors, and pseudo-classes)

标签选择器和伪元素(Element selectors and pseudo-elements)

通用选择器、子选择器和相邻兄弟选择器(Universal selectors, child combinators, and adjacent sibling combinators)

优先级是根据选择器的复杂度来计算的。优先级越高,规则越有可能被应用。

计算方法:

内联样式:1000

ID 选择器:100

类选择器、属性选择器和伪类:10

标签选择器和伪元素:1

通用选择器、子选择器和相邻兄弟选择器:0

如果两个规则具有相同的优先级,那么后导入的样式会覆盖先导入的样式。

:root:

:root 选择器表示文档的根元素,在 HTML 中就是 <html> 标签。

在 :root 中定义的 CSS 变量可以在整个文档中使用。

--background 和 --foreground:

--background 和 --foreground 是自定义的 CSS 变量。

--background 被设置为白色(#ffffff)。

--foreground 被设置为深灰色(#171717)

@media (prefers-color-scheme: dark):

这是一个媒体查询,用于检测用户的偏好颜色方案是否为暗模式。

prefers-color-scheme: dark 会匹配用户设置了暗模式的情况。

--background 和 --foreground 的重定义:

在暗模式下,--background 被重新设置为深黑色(#0a0a0a)。

--foreground 被重新设置为浅灰色(#ededed)。

color 和 background:

color 属性使用 var(--foreground) 变量,这意味着文本颜色会根据用户的颜色方案(亮模式或暗模式)自动调整。

background 属性使用 var(--background) 变量,这意味着背景颜色也会根据用户的颜色方案自动调整。

font-family:

font-family 属性设置了默认的字体系列,使用 Arial、Helvetica 和 sans-serif 作为备选字体。

要使表格更加紧凑,可以通过调整 CSS 样式来减少单元格的内边距(padding)、边框宽度(border-width)以及其他相关的间距属性。以下是具体的调整步骤和代码示例:

  1. 减少单元格内边距

通过减少 p-2 类中的内边距值,可以使表格单元格更加紧凑。

  1. 调整边框宽度

可以将边框宽度从 border 改为更细的边框,例如 border-t 和 border-b 来减少水平方向的边框。

  1. 调整表格整体宽度

可以将表格的宽度从 w-full 改为一个固定宽度或百分比宽度,以控制表格的整体尺寸。

减少外边距和内边距:

将 p-4 改为 p-2 或 p-1。

将 mb-4 改为 mb-2。

将 px-2 py-1 改为 px-1 py-0.5。

调整边框:

将 border 改为 border-t border-b,以减少水平方向的边框。

调整表格整体宽度:

保持 w-full,但可以根据需要调整为固定宽度或百分比宽度。

mt-2: 设置上外边距(margin-top)为 0.5rem(即 8px)。这是为了在该 div 的上方添加一些间距。

flex: 使用 Flexbox 布局,使得子元素可以按照 Flexbox 规则进行排列。

justify-between: 在主轴(默认为水平轴)上将子元素均匀分布,第一个子元素在起始位置,最后一个子元素在结束位置。

items-center: 在交叉轴(默认为垂直轴)上将子元素居中对齐。

综合起来,这段代码的作用是创建一个具有 Flexbox 布局的 div,其中子元素会在水平方向上均匀分布,并且在垂直方向上居中对齐。这个 div 还会在其上方添加一些间距。

container mx-auto p-4 是 Tailwind CSS 类,container 类会自动设置最大宽度,并使其居中,mx-auto 使容器水平居中,p-4 添加内边距。

为了清晰地展示页面的边界,你可以通过多种方式来实现,包括添加边框、背景颜色、阴影效果等。以下是几种常见的方法:

  1. 添加边框

你可以在父容器上添加边框,以便更清楚地看到其边界。例如:

从你提供的 RootLayout 组件来看,page.tsx 不是最顶层的组件。RootLayout 是 Next.js 应用程序的根布局组件,它包裹了所有的页面组件(包括 page.tsx)。以下是详细的解释:

  1. 根布局组件 (RootLayout)

RootLayout 是 Next.js 应用程序的根布局组件,定义在 app/layout.tsx 或类似的文件中。它负责定义整个应用程序的基本结构和样式。

RootLayout: 根布局组件,包裹所有页面组件。

page.tsx: 具体的页面组件,代表一个具体的页面。

因此,page.tsx 不是最顶层的组件,而是被 RootLayout 包裹的一个页面组件。

  1. 确保页面占满整个视口

为了确保 page.tsx 占满整个视口,你需要确保 RootLayout 和 page.tsx 的样式设置正确。以下是具体的步骤:

4.1 设置 RootLayout 的样式

确保 RootLayout 的 body 标签高度为 100%。

? 表示这个属性是可选的 。也就是说,使用该类型的对象时,onRowClick 不一定是必需的。如果父组件没有提供 onRowClick 回调函数,那么它将不会被触发。

  • onRowClick 的情况 :如果父组件传递了 onRowClick 函数,那么当用户点击某一行时,该函数将被调用。
  • 没有 onRowClick 的情况 :如果父组件没有传递 onRowClick 函数,那么点击行时不会触发任何回调。

3. (rowId: number | string) => void 回调函数签名

这部分定义了 onRowClick 回调函数的参数和返回值类型:

  • 参数 rowId :回调函数接受一个参数 rowId,表示被点击行的唯一标识符。rowId 的类型可以是 numberstring,这意味着它可以是一个数字或字符串,具体取决于你如何标识每一行。

    • number:如果你使用数字作为行的唯一标识符(例如,数据库中的自增 ID),那么 rowId 将是一个数字。
    • string:如果你使用字符串作为行的唯一标识符(例如,UUID 或其他字符串格式的 ID),那么 rowId 将是一个字符串。
  • 返回值 void :回调函数不返回任何值。void 表示该函数的执行结果是空的,即它不会返回任何数据。

回调函数定义

通过将 onRowClick 定义为回调函数,你可以实现父子组件的解耦 。这意味着子组件(例如 TableComponent)不需要知道父组件(例如 App)的具体实现细节,它只需要负责触发事件,而具体的业务逻辑由父组件来处理。

  • 子组件的责任TableComponent 只负责渲染表格,并在用户点击某一行时调用传递给它的 onRowClick 回调函数。
  • 父组件的责任App 组件可以根据业务需求定义 onRowClick 的具体行为,例如导航到详情页面、显示模态框、更新状态等。

这种方式使得代码更加模块化和可维护,因为每个组件只关心自己的职责,而不依赖于其他组件的内部实现。

使用回调函数可以让你根据不同的场景灵活地定义不同的行为。假设你有多个地方使用了 TableComponent,但每次点击行时的行为不同:

  • 在一个页面上,点击行可能需要导航到该行的详细信息页面。
  • 在另一个页面上,点击行可能需要弹出一个编辑表单。
  • 在第三个页面上,点击行可能只是简单地高亮该行。

通过将 onRowClick 定义为回调函数,你可以在不同的地方传递不同的实现,而不需要修改 TableComponent 的代码。这大大提高了组件的复用性和灵活性。

回调函数 是一种编程模式,其中一个函数作为参数传递给另一个函数,并在适当的时机被调用。通过这种方式,父组件可以定义具体的业务逻辑,而子组件只需要负责触发事件并调用回调函数。

1. 将函数作为参数传递

是的,回调函数的核心思想就是将函数作为参数传递。JavaScript 中的函数是一等公民(first-class citizens),这意味着你可以像传递其他类型的值(如数字、字符串)一样传递函数。你可以将函数作为参数传递给另一个函数,并在适当的时候调用它。

2. 父组件实现,子组件调用

在 React 中,父组件可以通过 props 将回调函数传递给子组件。子组件可以在特定事件发生时(例如用户点击某一行),调用这个回调函数并将相关数据(如 rowId)作为参数传递回去。父组件可以根据传回的数据执行相应的业务逻辑。

在 React 中,数据流是单向的,即父组件通过 props 向子组件传递数据,而子组件不能直接修改父组件的状态。但是,子组件可以通过回调函数将事件或数据传递回父组件,从而让父组件根据这些信息更新自己的状态。

  1. 子组件触发事件 :用户点击表格中的一行,触发 onClick 事件。
  2. 子组件调用回调函数onClick 事件处理器调用父组件传递的 onRowClick 回调函数,并将 row.id 作为参数传递给它。
  3. 父组件更新状态 :父组件中的 handleRowClick 回调函数被调用,接收 row.id 作为参数,并更新父组件的状态(例如,设置 isModalOpentrue,并保存 selectedRowId)。
  4. 父组件重新渲染 :由于父组件的状态发生了变化,React 会重新渲染父组件及其子组件。此时,弹窗会根据 isModalOpen 的值显示出来,并显示选中的行 ID。

关键点:子组件无法直接修改父组件的状态

你提到"子组件显然是无法修改父组件里的数据的",这是正确的。在 React 中,子组件确实不能直接修改父组件的状态。但是,通过回调函数 ,子组件可以将事件或数据传递给父组件,父组件可以根据这些信息更新自己的状态。这就是为什么我们说 React 的数据流是单向的,但仍然可以通过回调函数实现从子组件到父组件的通信。

在 JavaScript 中,函数调用确实会形成一个调用栈,但 React 的事件处理机制并不是基于递归调用栈的工作方式。相反,React 使用的是合成事件系统,它会将事件处理程序绑定到最外层的 DOM 节点上,并通过事件冒泡机制将事件传递给相应的组件。

具体来说,当用户点击表格中的一行时:

  • 事件首先被捕获并传递给最外层的 DOM 节点(例如,documentbody)。
  • 然后,React 会根据事件的目标元素(即被点击的行),找到对应的 React 组件(即 TableComponent)。
  • 最后,React 会调用该组件的事件处理程序(即 onClick),并执行回调函数。

因此,虽然子组件不能直接修改父组件的状态,但它可以通过回调函数将事件或数据传递给父组件,父组件再根据这些信息更新自己的状态。这种设计确保了数据流的单向性,同时保持了组件之间的解耦和灵活性。

总结

  • 父组件管理状态:父组件负责维护是否弹出弹窗的状态,并提供回调函数来更新这个状态。
  • 子组件触发回调函数:子组件在用户点击某一行时调用父组件传递的回调函数,并将行 ID 作为参数传递给父组件。
  • 父组件更新状态:父组件根据传回的行 ID 更新自己的状态(例如,显示弹窗)。
  • 单向数据流:子组件不能直接修改父组件的状态,但可以通过回调函数将事件或数据传递给父组件,由父组件决定如何处理。

React.useMemo

在使用 React.useMemo 时,有两个主要参数:factory 函数 和 依赖数组(deps)。下面分别解释这两个概念以及你在代码中提到的 classes.map((cls) => 中的 cls: Class 的含义。

定义:factory 是一个函数,返回你想要缓存的值。

作用:当依赖数组中的值发生变化时,factory 函数会被重新执行,计算新的值;否则,会返回之前缓存的值。

依赖数组(deps)

定义:deps 是一个数组,包含所有在 factory 函数中使用的外部变量。

作用:当数组中的任何一个变量发生变化时,factory 函数会被重新执行;否则,useMemo 返回缓存的值。

定义:classes.map((cls) => { ... }) 是对 classes 数组中的每个元素进行遍历,并对每个元素执行提供的回调函数。

cls: Class:

cls 是 classes 数组中的每一个元素。

Class 是 TypeScript 中的类型注解,表示 cls 的类型是 Class。

这个类型注解是由你的 IDE(如 IntelliJ IDEA)自动推断出来的,基于 classes 数组的类型定义。

相关推荐
rocky1915 分钟前
谷歌浏览器插件 录制元素拖动事件
前端·javascript
coder777723 分钟前
js逆向分享
javascript·爬虫·python·算法·安全
nothingbutluck46430 分钟前
2025.4.10 html有序、无序、定义列表、音视频标签
前端·html·音视频
爱上python的猴子1 小时前
chrome中的copy xpath 与copy full xpath的区别
前端·chrome
Lysun0012 小时前
dispaly: inline-flex 和 display: flex 的区别
前端·javascript·css
Moon里2 小时前
【React】什么是 Hook
react.js
山禾女鬼0012 小时前
Vue 3 自定义指令
前端·javascript·vue.js
啊卡无敌2 小时前
Vue 3 reactive 和 ref 区别及 失去响应性问题
前端·javascript·vue.js
北桥苏2 小时前
Spine动画教程:皮肤制作
前端
涵信2 小时前
第九节:React HooksReact 18+新特性-React 19的use钩子如何简化异步操作?
前端·javascript·react.js