炫酷的圆环加载及数字滚动效果(上)
栏目: JavaScript · 发布时间: 5年前
内容简介:实际项目开发时候需要实现圆环加载及数字滚动的效果,接下来分享下自己的实现思路和做法。vue本身就是根据数据来驱动view层的显示,实现数字的滚动本质就是设置一个延迟函数改变数据的同时,view层的显示也会随着改变达到渐变的效果。为了考虑多种使用场景,将滚动抽离成组件,需要用到的属性
实际项目开发时候需要实现圆环加载及数字滚动的效果,接下来分享下自己的实现思路和做法。
数字的滚动的实现思路
vue本身就是根据数据来驱动view层的显示,实现数字的滚动本质就是设置一个延迟函数改变数据的同时,view层的显示也会随着改变达到渐变的效果。
组件化
为了考虑多种使用场景,将滚动抽离成组件,需要用到的属性
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
tag | 标签名 | String | 'span' |
start | 是否开始 | Boolean | true |
startVal | 起始值 | Number / String | 0 |
endVal | 结束值 | Number /String | - |
decimals | 几位小数 | Number | 2 |
duration | 过渡时间 | Number | 2 (s) |
isRestart | 是否可以暂停 | Boolean | false |
所以我们props的类型校验如下
// 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 文件,在mounted中实例化了一个CountUp类,并且 向这个类中传递了我们props接收到的参数
。并且 在初始化和start值发生改变的时候
触发类中的 init函
数,在 endVal改变
的时候触发类的 updateNew函数
。最终通过render函数将值渲染在view层。分析完index.vue文件后,好奇到底countup.js定义了哪些函数,接下来看下数字过渡的实现。
CountUp类
首先我们来看代码结构,暂时不关心细节做了什么,constructor 构造函数
中接收到外部传入的值,并且将这些值添加到实例对象上。这样类上的方法( 也就是类的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(更新)......
实现代码逻辑。有了对这个类结构的认识,我们来看看每个模块都做了什么事。
在mounted钩子中我们通过 this._countup.init()
初始化,在初始化过程中主要做了一些安全转换,判断传入的$el如果未字符串则获取对应id的DOM,否则将target本身就是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来控制number1来重新渲染,如果这里 用v-show则页面进入的时候就会开始加载过渡效果
。不是我们想要的效果。之所以number2要用v-show是将其隐藏掉,如果是 v-if直接消失在DOM会再触发transition的过渡效果
,过渡 将变成500->5000->500的效果
,我们只需要将其隐藏掉同时显示number1的过渡效果即可。
结语
我们完成了数字过渡的组件,首先通过index.vue的prop接受参数,将逻辑部分放在countup.js中通过引入后实例化这个类。在初始化和更新值的时候调用类中的方法达到更新DOM的效果。 下节将分享圆环加载的过渡效果
。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 圆环旋转加显隐的加载效果
- 炫酷的圆环加载及数字滚动效果(下)
- 使用canvas绘制圆环动效
- css点滴3—5种方式实现圆环
- 解--头条的算法面试题-圆环开关灯
- javascript – 谷歌圆环图表,包含未知数量的变量
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
拆掉互联网那堵墙
庄良基 / 经济日报出版社 / 2014-6 / 25.80
都在说道互联网、说道电子商务、说道移动APP、说道微信、说道互联网金融......我们该如何认识互联网?中小微企业该如何借力互联网?互联网很神秘吗?很高深莫测吗? 其实互联网并没有什么神秘的,也没有什么高深莫测的!互联网无非是人类发明的工具而已,既然是工具,我们就一定可以驾驭和使用它。既然可以双重使用,就理当让所有有人都容易掌握并轻松驾驭。 互联网离我们很远吗?互联网界的成功故事都是那......一起来看看 《拆掉互联网那堵墙》 这本书的介绍吧!