Material UI in React [ Day15 ] Navigation Stepper 步骤卡

Stepper

Stepper 通过编号的步骤传达进度,它提供了类似向导的工作流程。
他除了有前面提到的 Tabs 的属性外还有提供纪录进度的功能,可以通过将当前步进索引(从零开始)作为 activeStep 属性传递来控制步进器,Stepper方向是使用 orientation 属性设置的,所以如果要调整成垂直的状态只要设置成 orientation="vertical",alternativeLabel 属性则可以让标签的位置改再 icon 之下。

// 先设置step title
function getSteps() {
  return ['基本资料', '选择商品型号', '配送资讯'];
}
// 再设置step content,可以用其他组件来替换
function getStepContent(stepIndex) {
  switch (stepIndex) {
    case 0:
      return '基本资料页面...';
    case 1:
      return '选择商品型号页面...';
    case 2:
      return '配送资讯...';
    default:
      return 'step 未设定';
  }
}
// in export function
const [activeStep, setActiveStep] = React.useState(0);
const steps = getSteps();

const handleNext = () => {
  setActiveStep((prevActiveStep) => prevActiveStep + 1);
};

const handleBack = () => {
  setActiveStep((prevActiveStep) => prevActiveStep - 1);
};

const handleReset = () => {
  setActiveStep(0);
};
/*in return*/
<div className={classes.root}>
  <Stepper activeStep={activeStep} alternativeLabel>
    {steps.map((label) => (
      <Step key={label}>
        <StepLabel>{label}</StepLabel>
      </Step>
    ))}
  </Stepper>
  <div>
    {activeStep === steps.length ? (
      <div>
        <Typography className={classes.instructions}>填写完毕</Typography>
        <Button onClick={handleReset}>重置</Button>
      </div>
    ) : (
      <div>
        <Typography className={classes.instructions}>{getStepContent(activeStep)}</Typography>
        <div>
          <Button
            disabled={activeStep === 0}
            onClick={handleBack}
            className={classes.backButton}
          >
            上一步
          </Button>
          <Button variant="contained" color="primary" onClick={handleNext}>
            {activeStep === steps.length - 1 ? '完成' : '下一步'}
          </Button>
        </div>
      </div>
    )}
  </div>
</div>

官网文件上有提供Skip的范例做法:

// ...前面的段落一样
// in export function
const classes = useStyles();
const [activeStep, setActiveStep] = React.useState(0);
const [skipped, setSkipped] = React.useState(new Set());
const isStepOptional = (step) => {
  return step === 1;
};

const isStepSkipped = (step) => {
  return skipped.has(step);
};

const handleNext = () => {
  let newSkipped = skipped;
  if (isStepSkipped(activeStep)) {
    newSkipped = new Set(newSkipped.values());
    newSkipped.delete(activeStep);
  }
  
  setActiveStep((prevActiveStep) => prevActiveStep + 1);
  setSkipped(newSkipped);
};

const handleBack = () => {
  setActiveStep((prevActiveStep) => prevActiveStep - 1);
};

const handleSkip = () => {
  if (!isStepOptional(activeStep)) {
    // 需要防范此情形,一般的使用情境下不太容易发生
    throw new Error("You can't skip a step that isn't optional.");
  }

  setActiveStep((prevActiveStep) => prevActiveStep + 1);
  setSkipped((prevSkipped) => {
    const newSkipped = new Set(prevSkipped.values());
    newSkipped.add(activeStep);
    return newSkipped;
  });
};

const handleReset = () => {
  setActiveStep(0);
};
<div className={classes.root}>
  <Stepper activeStep={activeStep}>
    {steps.map((label, index) => {
      const stepProps = {};
      const labelProps = {};
      if (isStepOptional(index)) {
        labelProps.optional =
        <Typography variant="caption">
            Optional
        </Typography>;
      }
      if (isStepSkipped(index)) {
        stepProps.completed = false;
      }
      return (
        <Step key={label} {...stepProps}>
          <StepLabel {...labelProps}>{label}</StepLabel>
        </Step>
      );
    })}
  </Stepper>
  <div>
    {activeStep === steps.length ? (
      <div>
        <Typography className={classes.instructions}>
          All steps completed - you&apos;re finished
        </Typography>
        <Button onClick={handleReset} className={classes.button}>
          Reset
        </Button>
      </div>
    ) : (
      <div>
        <Typography className={classes.instructions}>
          {getStepContent(activeStep)}
        </Typography>
        <div>
          <Button
            disabled={activeStep === 0}
            onClick={handleBack}
            className={classes.button}
          >
            Back
          </Button>
          {isStepOptional(activeStep) && (
            <Button
              variant="contained"
              color="primary"
              onClick={handleSkip}
              className={classes.button}
            >
              Skip
            </Button>
          )}

          <Button
            variant="contained"
            color="primary"
            onClick={handleNext}
            className={classes.button}
          >
            {activeStep === steps.length - 1 ? 'Finish' : 'Next'}
          </Button>
        </div>
      </div>
    )}
  </div>
</div>

可以依照实际的情况去修改逻辑,这个作法不是固定的。

Non-linear

设定 nonLinear 属性,可以让进程的线不亮。

<Stepper activeStep={activeStep} nonLinear alternativeLabel>
  {steps.map((label) => (
    <Step key={label}>
      <StepLabel>{label}</StepLabel>
    </Step>
  ))}
</Stepper>

另外还有类似 Carousel 的范例在官方的文件上,这里我就不再赘述他的用法了,因为我相信通常在处理这种 lightbox 的东西会去用类似 splidejs 这种专门的套件,可能会比较方便一些。
那麽今天的内容就到这里了,明天会讲解 Menu 组件的用法。


<<:  [Day 16] IOCP Input/Output Completion Port

>>:  Day 1 前言

DAY 23 『 客制化按钮 Custom Button 』

今天要介绍的是如何改变按钮的外观( 圆角、边线 ) 成品: 刻好画面後,在 ViewControll...

GitHub Action YAML 撰写技巧 - 环境变数(Environment Variables) 与 秘密 (Secrets)

今天要提到一些关於 GitHub Action 内撰写 YAML 一些技巧,环境变数 (Enviro...

第二十五天:用 dokka 产生 API 文件

当我们在写函式库或框架的时候,通常表示这段逻辑很常用到,希望藉由抽取成函式库或框架来重复使用,减少重...

Day23 - this&Object Prototypes Ch3 Objects - Review

Object content Array 是一种 Object,所以我们也能够用 key valu...

Python Flask 架站笔记 第2天 读取资料 网页框架 与爬虫

第二天的课程对於没有写过网页的我有一点难度,主要是网页的架构不像数据直线的思考,整个架构颇立体的, ...