从零实现一个灵活可扩展的Steps步骤条组件

UX-艳君 组件 阅读 2,883
赞 9 收藏
二维码
手机扫码查看
反馈

项目初期的技术选型

最近刚做完一个内部管理系统,里面用到了不少组件库的组件。其中有个功能是用户提交审批流程,设计稿里明确要求要有步骤条来显示当前进度。当时我第一反应是用 Ant Design 的 Steps 组件,毕竟它功能齐全,文档也够详细。

从零实现一个灵活可扩展的Steps步骤条组件

不过在实际开发前,我也纠结了一下要不要自己写个简单的步骤条组件。后来考虑到时间成本和维护性,还是决定用现成的。毕竟自己写的组件后续还得处理各种兼容性和样式问题,实在划不来。

最大的坑:动态步骤更新

开始用 Ant Design 的 Steps 挺顺利的,基本配置很快就搞定了。但很快我就遇到了第一个大坑:当用户点击“上一步”或“下一步”按钮时,步骤条需要实时更新当前状态,同时还要同步更新表单内容。

我的初始实现是直接通过 React 的 state 来控制当前步骤的索引值,代码大概是这样的:

import React, { useState } from 'react';
import { Steps, Button } from 'antd';

const { Step } = Steps;

const MySteps = () => {
  const [current, setCurrent] = useState(0);

  const next = () => {
    setCurrent(current + 1);
  };

  const prev = () => {
    setCurrent(current - 1);
  };

  return (
    <div>
      <Steps current={current}>
        <Step title="第一步" />
        <Step title="第二步" />
        <Step title="第三步" />
      </Steps>
      <div style={{ marginTop: 20 }}>
        {current > 0 && <Button onClick={prev}>上一步</Button>}
        {current < 2 && <Button onClick={next}>下一步</Button>}
      </div>
    </div>
  );
};

export default MySteps;

看起来没啥问题吧?结果测试的时候发现,当快速连续点击“下一步”按钮时,步骤条的状态会乱掉!比如本来应该从第一步跳到第二步,但有时候会直接跳到第三步。

折腾了半天才发现,问题出在异步更新上。React 的 setState 是异步的,所以如果用户快速点击按钮,state 的更新就会滞后,导致逻辑混乱。

最终的解决方案

为了解决这个问题,我调整了代码逻辑,确保每次点击按钮时都能正确地等待上一次的 state 更新完成再执行下一次操作。下面是改进后的代码:

import React, { useState } from 'react';
import { Steps, Button } from 'antd';

const { Step } = Steps;

const MySteps = () => {
  const [current, setCurrent] = useState(0);

  const next = () => {
    setCurrent((prevCurrent) => {
      const newCurrent = prevCurrent + 1;
      if (newCurrent <= 2) {
        // 这里可以添加一些额外的逻辑,比如表单验证
        return newCurrent;
      }
      return prevCurrent;
    });
  };

  const prev = () => {
    setCurrent((prevCurrent) => {
      const newCurrent = prevCurrent - 1;
      if (newCurrent >= 0) {
        return newCurrent;
      }
      return prevCurrent;
    });
  };

  return (
    <div>
      <Steps current={current}>
        <Step title="第一步" />
        <Step title="第二步" />
        <Step title="第三步" />
      </Steps>
      <div style={{ marginTop: 20 }}>
        {current > 0 && <Button onClick={prev}>上一步</Button>}
        {current < 2 && <Button onClick={next}>下一步</Button>}
      </div>
    </div>
  );
};

export default MySteps;

核心改动就是使用函数式 setState,这样可以确保每次状态更新都基于最新的 state 值,避免了异步更新带来的问题。

这里提醒一下:如果在项目中遇到类似的异步状态更新问题,优先考虑函数式 setState,亲测有效!

踩坑提醒:样式适配问题

解决了动态更新的问题后,我又遇到了另一个小麻烦:Ant Design 的 Steps 默认样式在某些分辨率下会显得特别拥挤,尤其是在小屏幕设备上。

起初我尝试通过修改全局样式来调整,但发现这样会影响其他页面的 Steps 样式。最后我选择用 CSS 的 scoped 样式来单独处理这个问题:

.my-steps .ant-steps-item {
  margin-right: 10px;
}

.my-steps .ant-steps-item-title {
  font-size: 14px;
}

然后在组件里加上类名:

<Steps current={current} className="my-steps">
  <Step title="第一步" />
  <Step title="第二步" />
  <Step title="第三步" />
</Steps>

虽然这不是最优雅的解法,但至少解决了眼前的问题。

回顾与反思

总的来说,这次用 Steps 步骤条的经历还算顺利,但也让我意识到一些需要注意的地方:

  • 动态状态更新一定要小心异步问题,尤其是涉及到用户交互的部分。
  • 样式适配是个老生常谈的问题,但在实际项目中还是会频繁出现。尽量用 scoped 样式来避免全局污染。
  • 虽然用现成的组件库能省不少事,但还是要对底层原理有一定的了解,不然遇到问题就容易抓瞎。

目前这个实现还有一些小瑕疵,比如在某些极端情况下,步骤条的动画效果会有点卡顿,但因为影响不大,暂时就没花时间去优化了。

结尾

以上是我个人对这个 Steps 步骤条组件的完整讲解,有更优的实现方式欢迎评论区交流。其实每个项目都会有一些意想不到的小坑,关键是要学会总结经验,下次再遇到类似问题就能更快解决了。

这个技巧的拓展用法还有很多,比如结合后端接口动态生成步骤条,或者在移动端做适配优化。后续我会继续分享这类博客,希望能帮到更多开发者。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论