来手写一个步骤条-steps效果

142 阅读3分钟

最近接手个新项目,项目技术原型让用jQuery来实现,系统框架也是用Jquery+layui来搭建的,作为组件库使用习惯了,好久没自己手写实现UI交互效果了,还好不算太费劲,记录一下子 效果这样子: image.png

css:

/* styles.css */
body {
  font-family: Arial, sans-serif;
  background-color: #ffffff;
  padding: 20px;
}

.steps {
  display: flex;
  padding: 20px;
  justify-content: space-between;
  margin-bottom: 20px;
  position: relative;
  background-color: #faf8f8;
}

.step {
  position: relative;
  flex: 1;
  text-align: center;
  cursor: pointer;
  z-index: 5;
}

.step-circle {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background-color: #ebeef5;
  color: #909399;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  margin: 0 auto;
  border: 1px solid #ebeef5;
}

.step-title {
  font-size: 18px;
  color: #909399;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 12px;
}

.step-sub-title {
  font-size: 14px;
  color: #909399;
  /* display: flex;
  align-items: center;
  justify-content: center; */
}

.step.active .step-circle {
  background-color: #122e9d;
  color: #fff;
  border-color: #122e9d;
}

.step.active .step-title {
  color: #0c0d0d;
}

.step.completed .step-circle {
  background-color: #0b0c0d;
  color: #fff;
  border-color: #0b0c0d;
}

.step.completed .step-title {
  color: #616161;
}

/* 使用伪元素 ::after 创建横线 */
.step:not(:first-child)::after {
  content: '';
  position: absolute;
  top: 15px;
  right: 60%;
  width: 80%;
  height: 1px;
  background-color: #676666;
  z-index: -1;
}

/* 确保当前步骤的横线颜色正确 */
.step.completed::after {
  background-color: #0b1014;
}

.step.active::after {
  background-color: #0b1014;
}

.step-content {
  width: 100%;
  height: 680px;
  overflow: scroll; /* 或者 overflow: auto */
  padding-bottom: 30px; /* 确保内容不会被固定在底部的按钮遮挡 */
}

/* 隐藏滚动条(适用于 WebKit 浏览器) */
.step-content::-webkit-scrollbar {
  display: none;
}

.step-pane {
  display: none;
}

.step-pane.active {
  display: block;
}

.step-controls {
  position: fixed;
  width: 94%;
  bottom: 0;
  right: 20px;
  padding: 10px;
  text-align: end;
  border-top: 1px solid #ebeef5;
}

.step-button {
  padding: 10px 20px;
  width: 130px;
  margin: 0 10px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  background-color: #185491;
  color: #fff;
}

.step-button.prev {
  background-color: #ebeef5;
  color: #909399;
}

.step-button.prev:hover {
  background-color: #d3dce6;
}

.step-button.next:hover {
  background-color: #1b5d9f;
}

js:

// script.js
document.addEventListener('DOMContentLoaded', function () {
  let totalSteps = 4; // 可以从外部传入
  let currentStep = 1; // 可以从外部传入

  function showStep(step, total) {
    document.querySelectorAll('.step').forEach(stepElement => {
      const stepNumber = parseInt(stepElement.getAttribute('data-step'));
      if (stepNumber < step) {
        stepElement.classList.add('completed');
        stepElement.classList.remove('active');
      } else if (stepNumber === step) {
        stepElement.classList.add('active');
        stepElement.classList.remove('completed');
      } else {
        stepElement.classList.remove('active', 'completed');
      }
    });

    // 切换 step-pane 的内容
    document.querySelectorAll('.step-pane').forEach(pane => {
      pane.classList.remove('active');
      if (parseInt(pane.getAttribute('data-step')) === step) {
        pane.classList.add('active');
      }
    });
    
    // 控制上一步按钮的显示与隐藏
    const prevButton = document.querySelector('.step-button.prev');
    if (step === 1) {
      prevButton.style.display = 'none';
    } else {
      prevButton.style.display = 'inline-block';
    }

    // 控制下一步按钮的显示与隐藏
    const nextButton = document.querySelector('.step-button.next');
    if (step === total) {
      nextButton.style.display = 'none';
    } else {
      nextButton.style.display = 'inline-block';
    }
  }

  function nextStep(currentStep, totalSteps) {
    if (currentStep < totalSteps) {
      currentStep++;
      showStep(currentStep, totalSteps);
    }
    return currentStep;
  }

  function prevStep(currentStep) {
    if (currentStep > 1) {
      currentStep--;
      showStep(currentStep, totalSteps);
    }
    return currentStep;
  }

  // 新增的方法:跳转到指定步骤
  function goToStep(step, totalSteps) {
    if (step >= 1 && step <= totalSteps) {
      currentStep = step;
      showStep(currentStep, totalSteps);
    } else {
      console.warn('Invalid step number');
    }
    return currentStep;
  }

  // 初始化显示第一步
  function initStep(step, total) {
    totalSteps = parseInt(total);
    currentStep = parseInt(step);
    showStep(currentStep, totalSteps);
  }
  window.initStep = initStep;

  // 添加按钮点击事件监听器
  document.querySelector('.step-button.prev').addEventListener('click', function (e) {
    e.preventDefault(); // 阻止默认行为
    currentStep = prevStep(currentStep, totalSteps);
  });

  document.querySelector('.step-button.next').addEventListener('click', function (e) {
    e.preventDefault(); // 阻止默认行为
    currentStep = nextStep(currentStep, totalSteps);
  });

  // 为所有 step 元素添加点击事件监听器
  document.querySelectorAll('.step').forEach(step => {
    step.addEventListener('click', function () {
      const stepNumber = parseInt(this.getAttribute('data-step'));
      currentStep = goToStep(stepNumber, totalSteps);
    });
  });
});

html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Element UI Steps Example</title>
    <link rel="stylesheet" href="./style.css" />
  </head>
  <body>
    <div style="width: 90vw; height: 90vh">
      <div class="steps">
        <div class="step" data-step="1">
          <div class="step-circle">1</div>
          <div class="step-title">油品出厂质量合格证</div>
          <div class="step-sub-title">Product Certificate of Quality</div>
        </div>
        <div class="step" data-step="2">
          <div class="step-circle">2</div>
          <div class="step-title">中转油库到货品质检查记录</div>
          <div class="step-sub-title">Intermediate Oil Depot Quality Control Records during Fuel Receipt</div>
        </div>
        <div class="step" data-step="3">
          <div class="step-circle">3</div>
          <div class="step-title">中转油库收油品质检查记录</div>
          <div class="step-sub-title">Intermediate Oil Depot Quality Control Records Fuel Receipt</div>
        </div>
        <div class="step" data-step="4">
          <div class="step-circle">4</div>
          <div class="step-title">中转油库重新评定检验报告</div>
          <div class="step-sub-title">Intermediate Oil Depot Recertification Test Report</div>
        </div>
        <div class="step" data-step="5">
          <div class="step-circle">5</div>
          <div class="step-title">中转油库发货品质检查记录</div>
          <div class="step-sub-title">Intermediate Oil Depot Release Certificate</div>
        </div>
        <div class="step" data-step="6">
          <div class="step-circle">6</div>
          <div class="step-title">油品接收条件检查</div>
          <div class="step-sub-title">Product Receipt Condition Check</div>
        </div>
      </div>
      <div class="step-content">
        <div class="step-pane active" data-step="1">
          <!-- 步骤1内容 -->
          111
        </div>
        <div class="step-pane" data-step="2">
          <!-- 步骤2内容 -->
          2222
        </div>
        <div class="step-pane" data-step="3">
          <!-- 步骤3内容 -->
          333
        </div>
        <div class="step-pane" data-step="4">
          <!-- 步骤4内容 -->
          444
        </div>
        <div class="step-pane" data-step="5">
          <!-- 步骤4内容 -->
          555
        </div>
        <div class="step-pane" data-step="6">
          <!-- 步骤4内容 -->
          666
        </div>
      </div>

      <div class="step-controls">
        <button class="step-button prev">上一步</button>
        <button class="step-button next">下一步</button>
      </div>
    </div>

    <script src="./script.js"></script>
    <script type="text/javascript">
      window.onload = function () {
        // 初始化显示第一步
        initStep(1, 6);
      };
    </script>
  </body>
</html>