Реализация идеи цифровой прокрутки
Vue сам управляет отображением слоя просмотра в соответствии с данными.Суть реализации прокрутки чисел заключается в том, чтобы установить функцию задержки для изменения данных, и отображение слоя просмотра также будет иметь постепенный эффект с изменением.
составной
Атрибуты, которые необходимо использовать для рассмотрения нескольких сценариев использования и разделения прокрутки на компоненты.
параметр | иллюстрировать | Типы | По умолчанию |
---|---|---|---|
tag | название ярлыка | String | 'span' |
start | стоит ли начинать | Boolean | true |
startVal | начальное значение | Number / String | 0 |
endVal | конечное значение | Number /String | - |
decimals | сколько десятичных знаков | Number | 2 |
duration | время перехода | Number | 2 (s) |
isRestart | Можно ли сделать паузу | Boolean | false |
Итак, проверка типа нашего реквизита выглядит следующим образом
// index.vue
<script>
import CountUp from './countup.js'
export default {
name: 'countup',
mounted() {
this.$nextTick(() => {
this._countup = new CountUp(
this.$el,
this.startVal,
this.endVal,
this.decimals,
this.duration
)
if (this.start) {
this._countup.init()
}
})
},
props: {
tag: {
type: String,
default: 'span'
},
start: {
type: Boolean,
default: true
},
startVal: {
type: Number | String,
default: 0
},
endVal: {
type: Number | String,
required: true
},
decimals: {
type: Number,
default: 2
},
duration: {
type: Number,
default: 2
},
isRestart: {
type: Boolean,
default: false
}
},
data() {
return {
times: 0
}
},
methods: {
onPauseResumeClick() {
if (this.isRestart) {
if (this.times === 0) {
this._countup.pauseResume()
this.times++
} else {
this._countup.restart()
this.times = 0
}
}
}
},
render(h) {
return h(
this.tag,
{
on: {
click: this.onPauseResumeClick
}
},
[this.startVal]
)
},
watch: {
start(val) {
if (val) {
this._countup.init()
}
},
endVal(val) {
this._countup.updateNew(this.endVal)
}
}
}
</script>
逻辑部分抽离出来放在 countup.js文件中
. Во-первых, давайте взглянем на файл index.vue, создадим экземпляр класса CountUp в смонтированном состоянии и向这个类中传递了我们props接收到的参数
. а также在初始化和start值发生改变的时候
в классе триггеровinit函
номер, вendVal改变
когда класс срабатываетupdateNew函数
. Наконец, значение визуализируется в слое представления с помощью функции рендеринга. Проанализировав файл index.vue, мне интересно, какие функции определяет countup.js, а затем посмотреть на реализацию цифрового перехода.
Класс обратного отсчета
Прежде всего, давайте посмотрим на структуру кода, подробности пока не интересны, конструктор构造函数
Получает переданные извне значения и добавляет эти значения в объект экземпляра. Такой метод в классе (也就是类的prototype原型上的方法
) Все будет хорошо通过this
Доступ к значению объекта экземпляра.
class CountUp {
constructor(target, startVal, endVal, decimals, duration) {
this.target = target
this.startVal = startVal
this.endVal = endVal
this.decimals = decimals
this.duration = Number(this.duration) * 1000 || 2000
}
// 初始化
init() {
// 拿到DOM
this.label =
typeof this.target === 'string'
? document.getElementById(this.target)
: this.target
this.startVal = Number(this.startVal)
this.endVal = Number(this.endVal)
this.frameVal = this.startVal
this.startTime = new Date()
this.progress = this.endVal - this.frameVal
this.update()
}
// 更新
update() {
this.rAF = setInterval(() => {
const time = new Date() - this.startTime
const speed =
((new Date() - this.startTime) / this.duration) * this.progress
if (time >= this.duration) {
clearInterval(this.rAF)
this.frameVal = this.endVal
this.startVal = this.frameVal
} else {
this.frameVal = this.startVal + speed
}
this.printValue(this.frameVal)
})
}
// 打印值
printValue(value) {
this.label.innerHTML = value.toFixed(this.decimals)
}
// 有新的结束值
updateNew(newEndVal) {
this.pauseResume()
this.endVal = newEndVal
this.init()
}
// 暂停
pauseResume() {
clearInterval(this.rAF)
this.startVal = this.frameVal
}
// 重新开始
restart() {
this.init()
}
}
export default CountUp
constructor
Получите данные в конструкторе, а затем передайте каждыйprototype
метод на如:printValue(打印值)、updateNew(更新)......
Реализовать логику кода. Вооружившись пониманием структуры этого класса, давайте посмотрим, что делает каждый модуль.
В навесной крючок проходимthis._countup.init()
Инициализация, в процессе инициализации в основном выполняются некоторые преобразования безопасности.Если входящий $el не является строкой, будет получен DOM соответствующего id.В противном случае целью будет сама DOM, а начальное и конечное значения будут преобразованы в числовые типы.开启计时
Установите startTime, мы будем использовать время, чтобы определить, достигнуто ли целевое значение, чтобы решить, следует ли остановить переход,计算出总的路程的绝对值
. По окончании инициализации начните выполнение следующегоexecute
функция.
переход
Самое главное в функции init — установить время начала перехода и рассчитать общее расстояние от начального значения до конечного значения. Далее идет процесс перехода цифровой прокрутки.
update() {
this.rAF = setInterval(() => {
const time = new Date() - this.startTime
const speed =
((new Date() - this.startTime) / this.duration) * this.progress
if (time >= this.duration) {
clearInterval(this.rAF)
this.frameVal = this.endVal
this.startVal = this.frameVal
} else {
this.frameVal = this.startVal + speed
}
this.printValue(this.frameVal)
})
}
существуетupdate更新函数
В мы устанавливаем setInterval для повторения выполнения числа累计过程
,пройти через单位时间/总时间*路程=速度
Формула для накопления, следует отметить, чтоspeed本身是有正负
Так что не нужно рассматривать, является ли это дополнительной или минусовой проблемой. И мы проходимprintValue
Функция обновляет значение каждого обновления в узле DOM. И управлять отображением DOM в этой функции, например toFixed, чтобы контролировать количество десятичных знаков, отображаемых числом, конечно, вы также можете контролировать整数部分每三位加一个,
отображение如:10,200
// 打印值
printValue(value) {
this.label.innerHTML = value.toFixed(this.decimals)
}
Пока мы завершили функцию перехода цифровой прокрутки, давайте посмотрим на эффект производства.
Хотя это было сделано, оказалось, что когда мы обновили конечное значение 5000 и изменили его на 500 до того, как оно было достигнуто, оно мгновенно изменилось обратно. // 有新的结束值
updateNew(newEndVal) {
this.pauseResume()
this.endVal = newEndVal
this.init()
}
// 暂停
pauseResume() {
clearInterval(this.rAF)
this.startVal = this.frameVal
}
мы должны更新endVal之前将上一个的定时器清除掉
, иначе он всегда будет использовать setInterval. Так в середине 500 -> 5000 меняем значение на 500, значит и startVal и endVal равны 500. Естественно эффекта перехода не будет, и значение 500 будет возвращено сразу. После добавления функции pauseResume посмотрите на эффект перехода.
isRestart为true是否开启可暂停模式
, судя по тому, правда ли это点击次数times
Пауза на 0, перезапустите прокрутку на 1.
methods: {
onPauseResumeClick() {
if (this.isRestart) {
if (this.times === 0) {
this._countup.pauseResume()
this.times++
} else {
this._countup.restart()
this.times = 0
}
}
}
},
render(h) {
return h(
this.tag,
{
on: {
click: this.onPauseResumeClick
}
},
[this.startVal]
)
},
Умело используйте v-if v-show, чтобы завершить преобразование карты в килокалорию.
// number1
<span v-if="isComplate">
<count :start-val="1"
:end-val="formatConsume"></count>千卡
</span>
// number2
<span v-show="!isComplate">
<count :start-val="0"
:end-val="1000"></count>卡
</span>
пройти черезv-if重新渲染和v-show显示隐藏的机制
, isComplate используется для оценки того, достигло ли оно 1000, здесь v-if используется для управления номером 1 для повторного рендеринга, если здесь用v-show则页面进入的时候就会开始加载过渡效果
. Не тот эффект, который нам нужен. Причина, по которой number2 использует v-show, состоит в том, чтобы скрыть его, если онv-if直接消失在DOM会再触发transition的过渡效果
,переход将变成500->5000->500的效果
, нам просто нужно скрыть его и показать эффект перехода number1.
Эпилог
Мы завершили компоненты цифрового перехода.Во-первых, мы принимаем параметры через реквизит index.vue, помещаем логическую часть в countup.js и создаем экземпляр этого класса после введения. Вызывайте методы в классе для обновления DOM при инициализации и обновлении значений.下节将分享圆环加载的过渡效果
.