table表格字段明细展示

发布于:2025-09-02 ⋅ 阅读:(20) ⋅ 点赞:(0)

表格字段明细展示,属于比较小的需求,但是也有一定交互细节,本文选取部分场景。

1、字段渲染

  • render和渲染组件是有区别的。
  • render常见为函数转化,利用页面和全局的变量state来渲染,最终返回Dom结构,偏向于展示和数据处理。函数参数和原来一致。
  • 渲染组件提供了自己的状态,有利于该字段的交互逻辑集中在组件中,尽量少利用外部变量。注意函数参数的变化,由props引入。
  • 命名方式略有不同,函数驼峰即可,组件大写字母开头+驼峰。
import { Table } from "antd";
import React, { useState } from "react";

const RenderNameCom = ({ text }) => {
  const [loading, setLoading] = useState(false);

  return (
    <div
      onClick={() => {
        setLoading(true);
        setTimeout(() => {
          setLoading(false);
        }, 2000);
      }}
    >
      {loading ? "Loading..." : text}
    </div>
  );
};

const renderNameFun = (text) => {
  const textLast = text > 10 ? "..." : text;
  return <div>{textLast}</div>;
};

export const columns = [
  {
    title: "Name",
    dataIndex: "name",
    render: (text) => <RenderNameCom text={text} />,
  },
  {
    title: "Age",
    dataIndex: "age",
    render: renderNameFun,
  },
];

const testPage = () => {
  return (
    <Table columns={columns} dataSource={[{ name: "John Doe", age: 32 }]} />
  );
};

export default testPage;

2、异步请求展示明细

  • click点击比较常见,单次点击也比较保守和稳定,配合disabled(或者loading)保证同一时间不在接受触发事件。
  • 获取展开状态visible(新版本使用open属性),可以进行灵活判断,不再进行触发请求。
  • 如果没有disabled禁用,连续点击触发多次,弹框
import { Table } from "antd";
import React, { useState } from "react";
import { Button, Popover, Spin, Divider } from "antd";

const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const RenderNameCom = ({ text }) => {
  const [show, setShow] = useState(false);
  const [loading, setLoading] = useState(false);
  const [data, setData] = useState({
    width: 0,
    height: 0,
    top: 0,
    left: 0,
  });

  const onClick = async () => {
  	// 当未展开时,点击可以发起请求;展开后,默认会关闭,阻止多余请求
    if (show) {
      return;
    }
    try {
      setLoading(true);
      await delay(2000);
      setData({
        width: 100,
        height: 100,
        top: 100,
        left: 100,
      });
      console.log("clicked");
      setLoading(false);
    } catch (error) {
      console.log(error);
      setLoading(false);
    }
  };
  return (
    <Popover
      content={
        loading ? (
          <Spin />
        ) : (
          <div>
            <p>Name: {text}</p>
            <Divider />
            <p>Width: {data?.width}</p>
            <p>Height: {data?.height}</p>
            <p>Top: {data?.top}</p>
            <p>Left: {data?.left}</p>
          </div>
        )
      }
      trigger="click"
      visible={show}
      onVisibleChange={(visible) => setShow(visible)}
    >
      <Button type="link" onClick={onClick} disabled={loading}>
        {text}
      </Button>
    </Popover>
  );
};

export const columns = [
  {
    title: "Name",
    dataIndex: "name",
    render: (text) => <RenderNameCom text={text} />,
  },
];

const testPage = () => {
  return (
    <Table columns={columns} dataSource={[{ name: "John Doe", age: 32 }]} />
  );
};

export default testPage;

3、hover展示问题

3.1 基本逻辑

  • 用click的基础代码,改为hover触发基本完成任务
  • 问题在于hover存在鼠标滑过频率很快的问题,误触发概率很大。
import { Table } from "antd";
import React, { useState } from "react";
import { Button, Popover, Spin, Divider } from "antd";

const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const RenderNameCom = ({ text }) => {
  const [show, setShow] = useState(false);
  const [loading, setLoading] = useState(false);
  const [data, setData] = useState({
    width: 0,
    height: 0,
    top: 0,
    left: 0,
  });

  const onClick = async () => {
    console.log("clicked start");
    if (show) {
      return;
    }
    try {
      setLoading(true);
      await delay(2000);
      setData({
        width: 100,
        height: 100,
        top: 100,
        left: 100,
      });
      console.log("clicked");
      setLoading(false);
    } catch (error) {
      console.log(error);
      setLoading(false);
    }
  };
  return (
    <Popover
      content={
        loading ? (
          <Spin />
        ) : (
          <div>
            <p>Name: {text}</p>
            <Divider />
            <p>Width: {data?.width}</p>
            <p>Height: {data?.height}</p>
            <p>Top: {data?.top}</p>
            <p>Left: {data?.left}</p>
          </div>
        )
      }
      trigger="hover"
      visible={show}
      onVisibleChange={(visible) => setShow(visible)}
    >
      <Button type="link" onMouseEnter={onClick} disabled={loading}>
        {text}
      </Button>
    </Popover>
  );
};

export const columns = [
  {
    title: "Name",
    dataIndex: "name",
    render: (text) => <RenderNameCom text={text} />,
  },
];

const testPage = () => {
  return (
    <Table
      style={{ paddingTop: "100px" }}
      columns={columns}
      dataSource={[{ name: "John Doe", age: 32 }]}
    />
  );
};

export default testPage;

3.2 hover时长判断

判断鼠标hover时长,决定是否触发事件;基础代码模拟。

const HoverTimer = () => {
  const [loading, setLoading] = useState(false);
  const timer = useRef(null);

  const onMouseEnter = async () => {
    timer.current = setTimeout(async () => {
      try {
        setLoading(true);
        await delay(2000);
        console.log("clicked");
        setLoading(false);
      } catch (error) {
        console.log(error);
        setLoading(false);
      }
    }, 1000);
  };

  const onMouseLeave = () => {
    if (timer.current) {
      clearTimeout(timer.current);
    }
  };

  return (
    <Button
      type="link"
      onMouseEnter={onMouseEnter}
      onMouseLeave={onMouseLeave}
      loading={loading}
    >
      Hover me
    </Button>
  );
};

3.3 render+hover

  • hover会自动展开和关闭,可以不再设置show的状态。
  • 注意hover刚开始,定时器未执行,利用defaultData的初始状态进行设置loading
import { Table } from "antd";
import React, { useState, useRef } from "react";
import { Button, Popover, Spin, Divider } from "antd";

const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const RenderNameCom = ({ text }) => {
  const [loading, setLoading] = useState(false);
  const defaultData = {
    width: 0,
    height: 0,
    top: 0,
    left: 0,
  };
  const [data, setData] = useState(defaultData);
  const timer = useRef(null);

  const onMouseEnter = async () => {
    console.log("clicked start");
    setData(defaultData); // 同步清空
    timer.current = setTimeout(async () => {
      try {
        setLoading(true);

        await delay(2000);
        setData({
          width: 100,
          height: 100,
          top: 100,
          left: 100,
        });
        console.log("clicked");
        setLoading(false);
      } catch (error) {
        console.log(error);
        setLoading(false);
      }
    }, 1000);
  };

  const onMouseLeave = () => {
    if (timer.current) {
      clearTimeout(timer.current);
    }
  };

  return (
    <Popover
      content={
        loading || data?.width === 0 ? (
          <Spin />
        ) : (
          <div>
            <p>Name: {text}</p>
            <Divider />
            <p>Width: {data?.width}</p>
            <p>Height: {data?.height}</p>
            <p>Top: {data?.top}</p>
            <p>Left: {data?.left}</p>
          </div>
        )
      }
      trigger="hover"
    >
      <Button
        type="link"
        onMouseEnter={onMouseEnter}
        onMouseLeave={onMouseLeave}
        disabled={loading}
      >
        {text}
      </Button>
    </Popover>
  );
};

export const columns = [
  {
    title: "Name",
    dataIndex: "name",
    render: (text) => <RenderNameCom text={text} />,
  },
];

const testPage = () => {
  return (
    <div>
      <Table
        style={{ paddingTop: "100px" }}
        columns={columns}
        dataSource={[{ name: "John Doe", age: 32 }]}
      />
    </div>
  );
};

export default testPage;

网站公告

今日签到

点亮在社区的每一天
去签到