vue-pure-admin步骤条组件:Steps流程步骤指示器

vue-pure-admin步骤条组件:Steps流程步骤指示器

【免费下载链接】vue-pure-admin 全面ESM+Vue3+Vite+Element-Plus+TypeScript编写的一款后台管理系统(兼容移动端) 【免费下载链接】vue-pure-admin 项目地址: https://gitcode.com/GitHub_Trending/vu/vue-pure-admin

还在为复杂的业务流程展示而烦恼?vue-pure-admin提供了强大而灵活的步骤条组件解决方案,帮助您轻松构建清晰直观的流程指示器。本文将深入解析项目中Steps组件的实现原理、使用方法和最佳实践。

步骤条组件概述

在vue-pure-admin中,Steps组件主要基于两个技术栈实现:

  1. Element Plus Steps - 基础步骤条组件
  2. PlusProComponents StepsForm - 高级步骤表单组件

核心特性对比

特性Element Plus StepsPlusProComponents StepsForm
基础步骤展示
表单集成
步骤验证
响应式设计
自定义样式
多步骤导航

Element Plus Steps 基础用法

基本步骤条实现

<template>
  <el-steps :active="currentStep" align-center>
    <el-step title="步骤一" description="创建项目" />
    <el-step title="步骤二" description="部门初审" />
    <el-step title="步骤三" description="财务复核" />
    <el-step title="步骤四" description="完成" />
  </el-steps>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const currentStep = ref(0)
</script>

带详细信息的步骤条

<template>
  <el-steps :active="2" class="w-[90%] m-auto">
    <el-step title="创建项目">
      <template #description>
        <p>负责人:张三</p>
        <p>2024-01-15 10:30:00</p>
      </template>
    </el-step>
    <el-step title="部门初审">
      <template #description>
        <p class="flex items-center">
          李四
          <el-button type="text" size="small">催一下</el-button>
        </p>
      </template>
    </el-step>
    <el-step title="财务复核" />
    <el-step title="完成" />
  </el-steps>
</template>

步骤条状态管理

<script setup lang="ts">
import { ref } from 'vue'

const steps = ref([
  { title: '步骤一', status: 'wait' },
  { title: '步骤二', status: 'process' },
  { title: '步骤三', status: 'wait' },
  { title: '步骤四', status: 'wait' }
])

const currentStep = ref(1)

// 下一步
const nextStep = () => {
  if (currentStep.value < steps.value.length - 1) {
    steps.value[currentStep.value].status = 'finish'
    currentStep.value++
    steps.value[currentStep.value].status = 'process'
  }
}

// 上一步
const prevStep = () => {
  if (currentStep.value > 0) {
    steps.value[currentStep.value].status = 'wait'
    currentStep.value--
    steps.value[currentStep.value].status = 'process'
  }
}
</script>

PlusProComponents StepsForm 高级用法

多步骤表单集成

<script setup lang="ts">
import { ref } from 'vue'
import { PlusStepsForm } from 'plus-pro-components'

const stepForm = ref([
  {
    title: "基本信息",
    form: {
      labelPosition: "top",
      style: { width: "400px", margin: "40px auto" },
      modelValue: {},
      columns: [
        {
          label: "项目名称",
          prop: "name",
          valueType: "input",
          rules: [{ required: true, message: "请输入项目名称" }]
        },
        {
          label: "项目状态",
          prop: "status",
          valueType: "select",
          options: [
            { label: "未开始", value: "0" },
            { label: "进行中", value: "1" },
            { label: "已完成", value: "2" }
          ]
        }
      ]
    }
  },
  {
    title: "详细配置",
    form: {
      modelValue: {},
      columns: [
        {
          label: "开始时间",
          prop: "startTime",
          valueType: "date-picker"
        },
        {
          label: "结束时间",
          prop: "endTime",
          valueType: "date-picker"
        }
      ]
    }
  }
])

const activeStep = ref(0)

const handleNext = (step: number, values: any) => {
  activeStep.value = step
  console.log('当前步骤:', step, '表单值:', values)
}
</script>

<template>
  <PlusStepsForm
    v-model="activeStep"
    :data="stepForm"
    align-center
    @next="handleNext"
  />
</template>

步骤表单验证流程

mermaid

自定义步骤条组件

创建可复用Steps组件

<!-- src/components/ReSteps/index.vue -->
<template>
  <div class="re-steps">
    <el-steps 
      :active="active" 
      :align-center="alignCenter"
      :simple="simple"
      :class="customClass"
    >
      <el-step
        v-for="(step, index) in steps"
        :key="index"
        :title="step.title"
        :description="step.description"
        :icon="step.icon"
        :status="getStepStatus(index)"
      />
    </el-steps>
    
    <div v-if="showNavigation" class="step-navigation mt-4">
      <el-button 
        v-if="active > 0" 
        @click="handlePrev"
        :disabled="active === 0"
      >
        上一步
      </el-button>
      
      <el-button 
        v-if="active < steps.length - 1" 
        type="primary" 
        @click="handleNext"
      >
        下一步
      </el-button>
      
      <el-button 
        v-if="active === steps.length - 1" 
        type="success" 
        @click="handleComplete"
      >
        完成
      </el-button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue'

interface Step {
  title: string
  description?: string
  icon?: string
}

interface Props {
  steps: Step[]
  active: number
  alignCenter?: boolean
  simple?: boolean
  showNavigation?: boolean
  customClass?: string
}

const props = withDefaults(defineProps<Props>(), {
  alignCenter: true,
  simple: false,
  showNavigation: true,
  customClass: ''
})

const emit = defineEmits(['update:active', 'next', 'prev', 'complete'])

const getStepStatus = (index: number) => {
  if (index < props.active) return 'finish'
  if (index === props.active) return 'process'
  return 'wait'
}

const handleNext = () => {
  if (props.active < props.steps.length - 1) {
    const newActive = props.active + 1
    emit('update:active', newActive)
    emit('next', newActive)
  }
}

const handlePrev = () => {
  if (props.active > 0) {
    const newActive = props.active - 1
    emit('update:active', newActive)
    emit('prev', newActive)
  }
}

const handleComplete = () => {
  emit('complete')
}
</script>

<style scoped>
.re-steps {
  @apply w-full;
}

.step-navigation {
  @apply flex justify-center gap-4;
}
</style>

使用自定义Steps组件

<template>
  <ReSteps
    :steps="steps"
    :active="currentStep"
    @next="handleStepNext"
    @prev="handleStepPrev"
    @complete="handleComplete"
  />
  
  <div class="step-content mt-6">
    <div v-if="currentStep === 0">
      <h3>基本信息</h3>
      <!-- 表单内容 -->
    </div>
    
    <div v-if="currentStep === 1">
      <h3>详细配置</h3>
      <!-- 表单内容 -->
    </div>
    
    <div v-if="currentStep === 2">
      <h3>确认信息</h3>
      <!-- 确认内容 -->
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import ReSteps from '@/components/ReSteps/index.vue'

const steps = ref([
  { title: '基本信息', description: '填写项目基础信息' },
  { title: '详细配置', description: '配置项目详细信息' },
  { title: '确认提交', description: '确认并提交项目' }
])

const currentStep = ref(0)

const handleStepNext = (step: number) => {
  console.log('下一步:', step)
  // 验证当前步骤数据
}

const handleStepPrev = (step: number) => {
  console.log('上一步:', step)
}

const handleComplete = () => {
  console.log('完成所有步骤')
  // 提交所有数据
}
</script>

高级功能实现

动态步骤管理

<script setup lang="ts">
import { ref, computed } from 'vue'

interface StepConfig {
  id: string
  title: string
  description?: string
  required?: boolean
  completed?: boolean
}

const steps = ref<StepConfig[]>([
  { id: 'base', title: '基本信息', required: true, completed: false },
  { id: 'config', title: '系统配置', required: true, completed: false },
  { id: 'advanced', title: '高级设置', required: false, completed: false },
  { id: 'review', title: '确认信息', required: true, completed: false }
])

const currentStepId = ref('base')

const currentStep = computed(() => {
  return steps.value.findIndex(step => step.id === currentStepId.value)
})

const completedSteps = computed(() => {
  return steps.value.filter(step => step.completed).length
})

const progress = computed(() => {
  const requiredSteps = steps.value.filter(step => step.required)
  const completedRequired = requiredSteps.filter(step => step.completed).length
  return (completedRequired / requiredSteps.length) * 100
})

const canProceed = computed(() => {
  const current = steps.value.find(step => step.id === currentStepId.value)
  return current?.completed || !current?.required
})

const navigateToStep = (stepId: string) => {
  const targetStep = steps.value.find(step => step.id === stepId)
  if (targetStep && (targetStep.completed || !targetStep.required)) {
    currentStepId.value = stepId
  }
}

const markStepCompleted = (stepId: string, completed: boolean = true) => {
  const step = steps.value.find(s => s.id === stepId)
  if (step) {
    step.completed = completed
  }
}
</script>

步骤条与路由集成

// src/router/utils.ts
import { RouteRecordRaw } from 'vue-router'

export interface StepRoute {
  path: string
  name: string
  title: string
  order: number
  required?: boolean
}

export const createStepRoutes = (steps: StepRoute[]): RouteRecordRaw[] => {
  return steps.map(step => ({
    path: step.path,
    name: step.name,
    component: () => import(`@/views/steps/${step.name}.vue`),
    meta: {
      step: step.order,
      stepTitle: step.title,
      required: step.required ?? true
    }
  }))
}

// 使用示例
export const projectSteps: StepRoute[] = [
  { path: 'base', name: 'ProjectBase', title: '基本信息', order: 1, required: true },
  { path: 'config', name: 'ProjectConfig', title: '配置设置', order: 2, required: true },
  { path: 'review', name: 'ProjectReview', title: '确认信息', order: 3, required: true }
]

最佳实践与性能优化

1. 步骤数据懒加载

<script setup lang="ts">
import { ref, shallowRef } from 'vue'

const steps = ref([
  { title: '步骤一', component: shallowRef(null) },
  { title: '步骤二', component: shallowRef(null) },
  { title: '步骤三', component: shallowRef(null) }
])

const currentStep = ref(0)

// 懒加载组件
const loadStepComponent = async (index: number) => {
  if (!steps.value[index].component.value) {
    const component = await import(`@/components/steps/Step${index + 1}.vue`)
    steps.value[index].component.value = component.default
  }
}

// 预加载下一步组件
const preloadNextStep = (currentIndex: number) => {
  const nextIndex = currentIndex + 1
  if (nextIndex < steps.value.length) {
    loadStepComponent(nextIndex)
  }
}
</script>

2. 步骤状态持久化

// src/utils/stepsPersist.ts
import { ref, watch } from 'vue'
import { useLocalStorage } from '@vueuse/core'

export const useStepsPersist = (key: string, initialSteps: any[]) => {
  const persistedData = useLocalStorage(key, {
    currentStep: 0,
    stepsData: initialSteps.map(() => ({}))
  })

  const currentStep = ref(persistedData.value.currentStep)
  const stepsData = ref(persistedData.value.stepsData)

  watch([currentStep, stepsData], ([newStep, newData]) => {
    persistedData.value = {
      currentStep: newStep,
      stepsData: newData
    }
  }, { deep: true })

  const clearPersistedData = () => {
    persistedData.value = {
      currentStep: 0,
      stepsData: initialSteps.map(() => ({}))
    }
  }

  return {
    currentStep,
    stepsData,
    clearPersistedData
  }
}

常见问题解决方案

1. 步骤验证失败处理

<script setup lang="ts">
import { ref } from 'vue'
import { ElMessage } from 'element-plus'

const currentStep = ref(0)
const steps = ref([...])

const validateCurrentStep = async (): Promise<boolean> => {
  try {
    // 根据当前步骤进行验证
    switch (currentStep.value) {
      case 0:
        return await validateStep1()
      case 1:
        return await validateStep2()
      case 2:
        return await validateStep3()
      default:
        return true
    }
  } catch (error) {
    ElMessage.error('步骤验证失败')
    return false
  }
}

const handleNext = async () => {
  const isValid = await validateCurrentStep()
  if (isValid && currentStep.value < steps.value.length - 1) {
    currentStep.value++
  }
}
</script>

2. 步骤间数据传递

// src/composables/useStepsData.ts
import { ref, reactive } from 'vue'

export const useStepsData = () => {
  const stepsData = reactive({
    step1: {
      name: '',
      type: '',
      description: ''
    },
    step2: {
      config: {},
      settings: {}
    },
    step3: {
      reviewData: {},
      confirmed: false
    }
  })

  const updateStepData = (step: keyof typeof stepsData, data: any) => {
    Object.assign(stepsData[step], data)
  }

  const getStepData = (step: keyof typeof stepsData) => {
    return { ...stepsData[step] }
  }

  const resetAllData = () => {
    Object.keys(stepsData).forEach(key => {
      const stepKey = key as keyof typeof stepsData
      if (Array.isArray(stepsData[stepKey])) {
        stepsData[stepKey] = [] as any
      } else {
        stepsData[stepKey] = {} as any
      }
    })
  }

  return {
    stepsData,
    updateStepData,
    getStepData,
    resetAllData
  }
}

总结

vue-pure-admin中的Steps组件提供了完整的流程步骤解决方案,从基础的步骤展示到复杂的多步骤表单处理,都能满足各种业务场景需求。通过合理的组件设计和状态管理,可以构建出用户体验优良的流程引导界面。

关键要点:

  • 根据业务复杂度选择合适的Steps组件(Element Plus或PlusProComponents)
  • 实现步骤状态管理和数据持久化
  • 优化步骤间导航和验证逻辑
  • 考虑移动端适配和响应式设计

通过本文的详细解析和代码示例,您应该能够熟练地在vue-pure-admin项目中使用Steps组件来构建专业的流程步骤界面。

【免费下载链接】vue-pure-admin 全面ESM+Vue3+Vite+Element-Plus+TypeScript编写的一款后台管理系统(兼容移动端) 【免费下载链接】vue-pure-admin 项目地址: https://gitcode.com/GitHub_Trending/vu/vue-pure-admin

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值