Автор оригинала: Michael Xavier.
Пару лет назад я написал небольшую статью о создании отзывчивого прогресс-бара. С тех пор мои методы усовершенствовались, поэтому необходимо обновить статью.
Самое большое изменение заключается в том, что псевдоэлементы (before, after) больше не нужны. Теперь CSS более прост, DOM легче читать, и он гораздо более динамичен.
Итак, давайте попробуем еще раз.
Наша цель – создать простой и эффективный отзывчивый прогресс-бар, который делает следующее:
- Имеет четыре шага до завершения.
- Каждый шаг имеет состояние по умолчанию, активное и завершенное.
- Можно переходить от этапа к этапу до завершения.
Посмотрите живой пример на CodePen здесь.
HTML
Чтобы уменьшить избыточность и увеличить возможность повторного использования, мы отслеживаем все состояния в компоненте Vue. В DOM он динамически генерирует любое количество необходимых шагов.
Примечание: Этого можно добиться с помощью нативного JavaScript (ECMAScript) или любого другого фреймворка. Использование Vue приведено в демонстрационных целях.
Прогресс-бар использует базовую разметку. В нем есть:
- контейнер с вычисляемыми классами, основанными на текущем шаге: progressClasses
- статическая фоновая дорожка: progress__bg
- цикл, который итерирует каждый шаг и применяет классы stepClasses на основе текущего шага.
Каждый шаг имеет:
- progress__indicator, содержащий значок галочки, который виден, если шаг завершен.
- метку progress__label, содержащую текст метки для этого шага.
<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>
Для простоты progress__actions, управляющие направлением движения, вложены в саму полосу прогресса.
CSS (SCSS)
Здесь мы выполняем тяжелую работу. Определенные здесь классы будут динамически применяться JS в зависимости от текущего шага.
Во-первых, давайте выберем несколько цветов для работы:
$gray: #E5E5E5; $gray2: #808080; $blue: #2183DD; $green: #009900; $white: #FFFFFF;
Теперь определите класс .progress: контейнер, в котором хранится содержимое индикатора выполнения.
.progress { position: absolute; top: 15vh; width: 0%; height: 10px; background-color: $blue; transition: width .2s; }
Нашему индикатору прогресса нужен .progress__bg, по которому будут бежать шаги прогресса, как по дорожке. Он будет серым и будет покрываться цветной полосой по мере продвижения к следующему шагу.
.progress__bg { position: absolute; width: 100vw; height: 10px; background-color: $gray; z-index: -1; }
Каждый .progress__step содержит круглый шаг, который будет выделяться и заполняться по мере продвижения индикатора прогресса.
.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); } } }
Он также содержит круглый .progress__indicator и текст метки .progress__label. Их стили по умолчанию определены вне .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; }
Теперь снова продолжим вложение внутри .progress__step и определим шаг в его активном состоянии.
&.progress__step--active { color: $blue; font-weight: 600; }
Затем определите шаг в его завершенном состоянии. Примечание: стили по умолчанию для .progress__indicator и .progress__label переписываются, когда шаг находится в завершенном состоянии.
&.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
Как упоминалось ранее, все зависит от того, как вы реализуете логику шага, в каком контексте она реализуется, какие фреймворки и паттерны вы используете и т.д.
В данном примере для демонстрации используется компонент Vue:
- расчет классов для индикатора выполнения на основе текущего состояния.
- расчет классов для каждого шага на основе текущего состояния.
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}` } } })
Заключение
В конце всего этого у вас есть вот это:
Посмотрите живой пример на CodePen.
Оригинал: “https://www.freecodecamp.org/news/how-to-build-a-responsive-and-dynamic-progress-bar/”