组件开发--横向步骤条

177 阅读2分钟

要求

element-plus 组件库中的步骤条不满足UI设计稿

UI设计稿的样式antd是可以实现的,但是目前开发项目中用的是vue+element

所以自己写了个横向步骤条组件,实现该功能

UI样式

image.png image.png image.png

组件应用

 <RowSteps :active="step" :list="stepList" />
 
 const stepList = reactive([
  { step: 1, text: '接口基本设置', sucess: false },
  { step: 2, text: '选择交易流程 ', sucess: false },
  { step: 3, text: '完成', sucess: false },
]);
const step = ref(1);

/取消 和 上一步
const handleCancel = (formEl) => {
  if (!formEl) return;
  if (step.value === 1) {
    //取消
    formEl.resetFields();
    props.onClose();
  } else if (step.value === 2) {
    //上一步
    step.value = 1;
    delete rules.flowCode;
  }
};
//确定表单验证 下一步 和提交
const handleConfirm = async (formEl) => {
  if (!formEl) return;

  await formEl.validate((valid, fields) => {
    if (valid) {
      if (step.value === 1) {
        //点击下一步
        step.value = 2;
        //添加第二页的校验
        rules.flowCode = [
          {
            required: true,
            message: '请选择交易流程',
            trigger: 'change',
          },
        ];
      } else if (step.value === 2) {
        //提交
        submitLoading.value = true;
        handleSignIn();
        // //第三步 提交成功后再到第三步
        // step.value = 3;
      }
    } else {
      console.log('error submit!', fields);
    }
  });
};

组件代码

<!--
 * @Author: SunnyYang
 * @Date: 2024-01-20 18:00:48
 * @LastEditors: SunnyYang
 * @LastEditTime: 2024-03-02 19:50:53
 * @Description: 
-->
<template>
  <div class="form-step-box">
    <div class="step-item" v-for="(item, index) in stepList" :key="item.step">
      <el-icon v-if="status === 'icon' && item.success" class="success-icon-num"><CircleCheck /></el-icon>
      <span v-else :class="['num', item.step === activeValue && 'active-num', item.success && 'success-num']">
        {{ item.step }}
      </span>
      <span :class="['text', item.step <= activeValue ? 'active-text' : '']">{{ item.text }}</span>
      <span v-if="index + 1 !== stepList.length" :class="['line', item.step < activeValue && 'active-line']"></span>
    </div>
  </div>
</template>

<script setup name='RowSteps'>
import { ref, watch } from 'vue';

const props = defineProps({
  // 步骤条数据
  list: {
    type: Array,
    default: () => [
      // { step: 1, text: '接口基本设置', success: false }
    ],
  },
  active: {
    type: Number,
    default: 1,
  },
  status: {
    type: String,
    default: 'icon', //icon对勾 text数字
  },
});

const activeValue = ref(props.active),
  stepList = ref(props.list);
watch(
  () => props.active,
  () => {
    activeValue.value = props.active;
    //修改step
    stepList.value = stepList.value.map((v) => ({ ...v, success: v.step < activeValue.value }));
  },
);
</script>

<style lang="scss" scoped>
.form-step-box {
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;

  .step-item {
    display: inline-flex;
    align-items: center;
    flex-direction: row;
  }

  .num {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    display: flex;
    justify-content: center;
    align-items: center;
    margin: 0 10px;
    font-family: PingFang SC, PingFang SC;
    font-size: 14px;

    color: #999999;
    background-color: #fff;
    border: 2px solid #999999;
    font-weight: 600;
  }
  .active-num {
    color: #fff;
    background-color: #1d70f5;
    border: 2px solid #1d70f5;
  }
  .success-num {
    color: #fff;
    background-color: #00b42a;
    border: 2px solid #00b42a;
  }

  .success-icon-num {
    color: #00b42a;
    font-size: 24px;
    margin: 0 10px;
  }
  .text {
    font-family: PingFang SC, PingFang SC;
    font-size: 14px;
    font-weight: 500;
    color: #999999;
  }

  .active-text {
    font-weight: 600;
    color: #222222;
  }

  .success-text {
    font-weight: 600;

    color: #00b42a;
  }

  .line {
    width: 108px;
    height: 1px;
    background-color: #cccccc;
    margin-left: 10px;
  }

  .active-line {
    background-color: #00b42a;
  }
}
</style>

参考文档