Então, vamos tentar novamente.

Nosso objetivo é construir uma barra de progresso responsiva simples e eficaz que faça o seguinte:

  • Possui quatro etapas para conclusão.
  • Cada etapa tem um default, active, e complete Estado.
  • Pode progredir de etapa em etapa até a conclusão.

Confira o CodePen aqui para um exemplo ao vivo.

O HTML

Para reduzir a redundância e aumentar a capacidade de reutilização, rastreamos todos os estados em um componente Vue. No DOM, isso gera dinamicamente qualquer número de etapas necessárias.

Nota: JavaScript nativo (ECMAScript) ou qualquer outra estrutura pode fazer isso. O uso do Vue é para fins demonstrativos.

A barra de progresso usa marcação básica. Há sim:

  • um contêiner com classes calculadas com base na etapa atual: progressClasses
  • uma trilha estática de fundo: progress__bg
  • um loop que itera em cada etapa e se aplica stepClasses com base na etapa atual.

Cada etapa tem:

  • uma progress__indicator que contém um ícone de verificação que fica visível se a etapa for concluída.
  • uma progress__label que contém o texto do rótulo dessa etapa.

<div  id="app"  :class="progressClasses">  <div class="progress__bg"></div>    <template v-for="(step, index) in steps">    <div :class="stepClasses(index)">      <div class="progress__indicator">        <i class="fa fa-check"></i>      </div>      <div class="progress__label">        {{step.label}}      </div>    </div>  </template>    <div class="progress__actions">    <div      class="btn"      v-on:click="nextStep(false)"    >      Back    </div>    <div      class="btn"      v-on:click="nextStep"    >      Next    </div>    <div>      Step:      {{currentStep ? currentStep.label : "Start"}}    </div>  </div></div>

Para simplificar, o progress__actions que controlam a direção da viagem estão aninhados na própria barra de progresso.

O CSS (SCSS)

É aqui que fazemos o trabalho pesado. As classes definidas aqui serão aplicadas dinamicamente pelo JS com base na etapa atual.

Primeiro, vamos selecionar algumas cores para trabalhar:

$gray:  #E5E5E5;$gray2: #808080;$blue:  #2183DD;$green: #009900;$white: #FFFFFF;

Agora defina o .progress classe: o contêiner que mantém o conteúdo da barra de progresso junto.

.progress {  position: absolute;  top: 15vh;  width: 0%;  height: 10px;  background-color: $blue;  transition: width .2s;}

Nossa barra de progresso precisa de um .progress__bg que as etapas de progresso correrão como uma trilha. Ele ficará cinza, coberto pela barra colorida conforme avança para a próxima etapa.

.progress__bg {  position: absolute;  width: 100vw;  height: 10px;  background-color: $gray;  z-index: -1;}

Cada .progress__step contém a etapa circular que será destacada e preenchida conforme a barra de progresso avança.

.progress__step {  position: absolute;  top: -8px;  left: 0;  display: flex;  flex-direction: column;  align-items: center;  text-align: center;    @for $i from 1 through 5 {    &.progress__step--#{$i} {      left: calc(#{$i * 20}vw - 9px);    }  }}

Ele também contém a rodada .progress__indicator e texto do rótulo .progress__label. Seus estilos padrão são definidos fora do .progress__step.

.progress__indicator {  width: 25px;  height: 25px;  border: 2px solid $gray2;  border-radius: 50%;  background-color: $white;  margin-bottom: 10px;    .fa {    display: none;    font-size: 16px;    color: $white;  }}.progress__label {  position: absolute;  top: 40px;}

Vamos agora continuar a aninhar dentro .progress__step novamente e definir a etapa em seu ativo Estado.

&.progress__step--active {  color: $blue;  font-weight: 600;}

Em seguida, defina a etapa em seu completo Estado. Nota: os estilos padrão para .progress__indicator e .progress__label são substituídos quando no estado completo.

&.progress__step--complete {  .progress__indicator {    background-color: $green;    border-color: $blue;    color: $white;    display: flex;    align-items: center;    justify-content: center;  }      .progress__indicator .fa {    display: block;  }    .progress__label {    font-weight: 600;    color: $green;  }}

O JavaScript

Conforme mencionado anteriormente, isso será diferente com base em como você implementa a lógica de etapas, o contexto mais amplo em que é implementado, quais estruturas e padrões você usa e assim por diante.

Este exemplo usa um componente Vue para demonstrar:

  • cálculo de classes para a barra de progresso com base no estado atual.
  • cálculo de classes para cada etapa com base no estado atual.

var app = new Vue({  el: '#app',    data: {    currentStep: null,    steps: [      {"label": "one"},      {"label": "two"},      {"label": "three"},      {"label": "complete"}    ]  },    methods: {    nextStep(next=true) {      const steps = this.steps      const currentStep = this.currentStep      const currentIndex = steps.indexOf(currentStep)            // handle back      if (!next) {        if (currentStep && currentStep.label === 'complete') {          return this.currentStep = steps[steps.length - 1]                   }        if (steps[currentIndex - 1]) {          return this.currentStep = steps[currentIndex - 1]         }        return this.currentStep = { "label": "start" }         }            // handle next      if (this.currentStep && this.currentStep.label === 'complete') {        return this.currentStep = { "label": "start" }      }            if (steps[currentIndex + 1]) {        return this.currentStep = steps[currentIndex + 1]      }      this.currentStep = { "label": "complete" }       },        stepClasses(index) {      let result = `progress__step progress__step--${index + 1} `      if (this.currentStep && this.currentStep.label === 'complete' ||          index < this.steps.indexOf(this.currentStep)) {        return result += 'progress__step--complete'      }      if (index === this.steps.indexOf(this.currentStep)) {        return result += 'progress__step--active'      }      return result    }  },    computed: {     progressClasses() {      let result="progress "      if (this.currentStep && this.currentStep.label === 'complete') {        return result += 'progress--complete'      }      return result += `progress--${this.steps.indexOf(this.currentStep) + 1}`    }  }})

Conclusão

No final de tudo, você tem isso:

progress 1

Confira o CodePen para um exemplo ao vivo.

Se você achar meus artigos úteis, por favor, considere se tornar um membro de meu patreon 🙂

Ou se você só quer me comprar café (eu amo café):