Cu câțiva ani în urmă am scris un scurt articol la crearea unei bare de progres receptive. Tehnicile mele s-au dezvoltat de atunci, așa că o actualizare este în ordine.

Cea mai mare schimbare este că pseudo-elementele (înainte, după) nu mai sunt necesare. Acum CSS este mai simplu, DOM este mai ușor de citit și este mult mai dinamic.

Deci, să încercăm din nou acest lucru.

Obiectivul nostru este de a construi o bară de progres receptivă simplă și eficientă care să facă următoarele:

  • Are patru pași până la finalizare.
  • Fiecare pas are un default, active, și complete stat.
  • Poate progresa de la pas la pas până la finalizare.

Consultați CodePen aici pentru un exemplu live.

Codul HTML

Pentru a reduce redundanța și a crește reutilizarea, urmărim toate stările dintr-o componentă Vue. În DOM, acest lucru generează dinamic orice număr de pași necesari.

Notă: JavaScript nativ (ECMAScript) sau orice alt cadru poate realiza acest lucru. Utilizarea Vue este în scop demonstrativ.

Bara de progres utilizează marcajul de bază. Există:

  • un container cu clase calculate pe baza pasului curent: progressClasses
  • o pistă de fundal statică: progress__bg
  • o buclă care iterează prin fiecare pas și se aplică stepClasses pe baza pasului curent.

Fiecare pas are:

  • A progress__indicator care conține o pictogramă de verificare care este vizibilă dacă pasul este finalizat.
  • A progress__label care conține textul etichetei pentru acel pas.
<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>

Pentru simplitate, progress__actions care controlează direcția de deplasare sunt cuibărite în bara de progres în sine.

CSS (SCSS)

Aici facem greutăți mari. Clasele definite aici vor fi aplicate dinamic de către JS pe baza pasului curent.

Mai întâi, să selectăm câteva culori pentru a lucra:

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

Acum definiți .progress class: containerul care ține împreună conținutul barei de progres.

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

Bara noastră de progres are nevoie de un .progress__bg că pașii de progres vor rula ca o pistă. Acesta va fi gri, acoperit de bara colorată pe măsură ce avansează la pasul următor.

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

Fiecare .progress__step conține pasul rotund care va evidenția și umple pe măsură ce bara de progres avansează.

.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);
    }
  }
}

De asemenea, conține runda .progress__indicator și textul etichetei .progress__label. Stilurile lor implicite sunt definite în afara .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;
}

Să continuăm acum să cuibărim înăuntru .progress__step din nou și definiți pasul în activ stat.

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

Apoi, definiți pasul în complet stat. Notă: stilurile implicite pentru .progress__indicator și .progress__label sunt suprascrise când sunt în stare completă.

&.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;
  }
}

JavaScript

Așa cum am menționat mai devreme, acest lucru va diferi în funcție de modul în care implementați logica pasului, contextul mai larg în care este implementat, ce cadre și tipare utilizați etc.

Acest exemplu folosește o componentă Vue pentru a demonstra:

  • calculul claselor pentru bara de progres pe baza stării curente.
  • calculul claselor pentru fiecare pas pe baza stării curente.
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}`
    }
  }
})

Concluzie

La sfârșitul tuturor, aveți acest lucru:

Cum sa construiti o bara de progres dinamica si receptiva

Consultați CodePen pentru un exemplu live.

Dacă vi se par utile articolele mele, vă rugăm să luați în considerare deveniți membru al Patreonul meu 🙂

Sau dacă vrei doar să-mi cumperi cafea (îmi place cafeaua):