内容简介:要用到柱状图,第一时间想到去echart看看示例扒一套代码下来。看了官方教程后感觉不太适合本项目,考虑后觉得自己动手写个图标比较省事而且不用引包。那就开始吧!滚动图表首先得有一些柱子呀,那我们就来早柱子,这些都是个宽度相等,高度给父级设置flex,设置交叉轴的对其方式为flex-end就可以把柱子都立起来了。但是可以看到日期和柱子是同时滚动的,它们应该同级的标签。
要用到柱状图,第一时间想到去echart看看示例扒一套代码下来。看了官方教程后感觉不太适合本项目,考虑后觉得自己动手写个图标比较省事而且不用引包。那就开始吧!
柱状图
滚动图表首先得有一些柱子呀,那我们就来早柱子,这些都是个宽度相等,高度 按比例*设定好的最高高度
的柱子。通过flex布局就可以实现这些。
<div class="move__wrap"> <div class="move__item" v-for="member in list" :key="member.id"></div> </div> // style <style lang='scss' scoped> .move { &__wrap { display: flex; align-items: flex-end; height: 100%; } } </style> 复制代码
给父级设置flex,设置交叉轴的对其方式为flex-end就可以把柱子都立起来了。但是可以看到日期和柱子是同时滚动的,它们应该同级的标签。
<div class="move__wrap"> <div class="move__item" v-for="member in list" :key="member.id"> // 柱子 <div class="child__chart"></div> // 日期 <div></div> </div> </div> // style <style lang='scss' scoped> .move { &__wrap { display: flex; align-items: flex-end; height: 100%; } &__item{ display: flex; flex-wrap: wrap; width: 38px; } } </style> 复制代码
设置两个弹性盒子之后柱状图和日期都已经出来了。需要注意的一点是每个柱状图之间是有间隙的,但是日期是没有间隙的。 我们不能直接给move__item设置左外边距,将 child__chart设置宽度为37并且设置margin-left:1就有了如下图表
这里还需要定一个图标的最高的高度。比如想定最高的高度为180,我这里的做法是找出list中最大的一个值,其他项以它为标准做百分百比运算。
// @param {Array} list 数组项为数字即步数 <div class="move__item" v-for="member in list" :key="member.id"> <div class="child__chart" :style="{height:member/maxStep*180+'px'}"></div> </div> // js computed:{ // 找出最大值参考 maxStep() { let max = 0 this.seriesDataList.forEach(number => { max = number > max ? number : max }) return max }, } 复制代码
动起来
到此柱状图我们已经完成了,现在的目标就是让这个图表滑动起来。 这里我们需要了解一些css属性。
overflow-x : 当一个块级元素的内容在水平方向发生溢出时,应该截断溢出内容,或者显示滚动条,或者直接显示溢出内容。 visible | hidden | clip | scroll | auto 。
overflow-y : 同上。
-webkit-scrollbar : CSS伪类选择器影响了一个元素的滚动条的样式 可以设置css属性,这里使用none值隐藏滚动条
以上属性设置了是否滚动及滚动条的样式,我们还需要知道形成滚动的条件。
- 有父子两个元素
- 子元素的高/宽 > 父元素的高/宽
你也可以点击这里查看更多
光有滚动还不行,我们还需要监听滚动到哪里了获取到信息。用到了target.addEventListener(type, listener[, options])
EventTarget.addEventListener() 方法 : 将指定的监听器注册到 EventTarget 上,当该对象触发指定的事件时,指定的回调函数就会被执行。
- type 表示监听事件类型的字符串这里我们用到的是scroll
- listener 需要执行的函数,考虑到之后要根据条件去removeEventListener移除事件监听,我们可以在data函数中定义一个有名的listener
- options 表示是在冒泡阶段或者捕获阶段会触发listener,默认为false即在冒泡阶段触发。
- eventTarget 事件目标可以是一个文档上的元素我们在
mounted钩子中
通过ref获取到我们目标值上,需要注意的滚动监听事件要绑定在滚动元素父级的DOM
data(){ return { scrollListenHandle: () => { console.log(this.$refs.scroll.scrollLeft) this.scrollLength = this.$refs.scroll.scrollLeft } } }, mounted() { this.$refs.scroll.addEventListener('scroll', this.scrollListenHandle) } 复制代码
现在我们已经设置好x轴方向的滚动效果和了滚动事件来看看效果吧
高亮
我们已经将图表滚起来了,我们需要将当前选中的日期高亮起来。这里涉及到一个参考,默认让图标可视区域的中心点的柱子高亮。
怎么拿到这个中心点呢?假设我们一页可以显示九根柱子,每根柱子的宽度是38px,当我们向右移动38px时,则第六根柱子会亮起来。计算公式可以是`(移动的距离+半个屏幕宽度)/38`就是当前移动时需要高亮的柱子的序号
data(){ // 滚动时不断更新scrollLength滚动距离 scrollListenHandle: () => { this.scrollLength = this.$refs.scroll.scrollLeft }, }, mounted() { // 获取当前屏幕的宽度 this.screenWidth = screen.width }, computed:{ // 获取到当前高亮的目标值的序号 selectIndex() { return parseInt( (this.scrollLength + this.screenWidth / 2) / singleWidth ) }, } 复制代码
通过滚动事件将滚动的距离更新,通过计算属性得到当前选中柱子的序号,有了这个序号我们可以通过vue的动态绑定class设定高亮的样式。html代码如下:
<div ref="scroll" class="chart__move" @touchmove="onTouchMove"> <div ref="child" class="move__child" :style="{width:AllLength + 'px'}"> <div v-for="(item,index) in chartList" :key="index" class="child__wrap"> <div class="child__chart" :class="{'child__chart--white':selectIndex === index}" :style="{height:item/maxStep*180+'px'}"></div> <div class="child__date" :class="{'child__date--blue':selectIndex === index}">{{dateList[index]}}</div> </div> </div> </div> 复制代码按照我们的做法高亮的柱子
范围限定在 this.screenWidth / 2 ~ 总长度 - this.screenWidth / 2
在除了这个返回之外的柱子我们只能通过点击让它高亮,
毕竟已经到头了或者到尾了没办法移动了
。这里又涉及到一个问题,当我们点击柱子时,如果还在
范围限定在 this.screenWidth / 2 ~ 总长度 - this.screenWidth / 2
中的柱子,当我们点击它时,应该将它移动到中间的位置上来。
这里我们需要通过this.$refs.scroll.scrollLeft赋值来达到效果
。
页面一共九根柱子时,点击第6根柱子时,将序号传给 onSelectDateClick事件,我们要做的两件事,让第6根柱子亮起来。这很简单,使用:class动态绑定即可。还需要做的是将滚动元素的scrollLeft值增加38px(一个柱子的宽度)。这样做效果是达到了,但是我们需要点击的时候需要有一个过渡的效果,也就是慢慢移过去。可以设置一个过渡时间。好的下面就开始干吧!
// 定义数字的含义避免魔法数 而且方便统一修改 const singleWidth = 38 // 单个柱子的宽度 const duration = 100 // 过渡时间 export default { methods:{ onSelectDateClick(index) { // 获取到高亮的index this.clickIndex = index // 目标的scroolLeft const targetLeft = index * singleWidth - this.screenWidth / 2 // 当前的scrollLeft this.currentLeft = this.$refs.scroll.scrollLeft // 每秒的速度 this.speed = (targetLeft - this.currentLeft) / duration // 记下开始的时间 this.startTime = new Date() // 开始过渡函数 this.update() }, update() { // 定时更新 this.$refs.scroll.scrollLeft this.rAF = setInterval(() => { const time = new Date() - this.startTime this.$refs.scroll.scrollLeft = time * this.speed + this.currentLeft // 如果时间超过我们预定的过渡时间就停止更新 if (time > duration) { clearInterval(this.rAF) } }) }, } } 复制代码
为了避免干扰html 动态绑定class设置为
:class="{'child__chart--white':clickIndex===index}" 复制代码
来看下效果
看起来不错,我们继续把selectIndex加上,现在类名高亮受两个index决定
:class="{'child__chart--white':selectIndex === index||clickIndex===index}" 复制代码
当我通过点击改变 scrollLeft的值时会也会触发滚动事件,当selectIndex和clickIndex不同时会出现两个高亮的柱子。我们需要一个值来区分现在是现在是滚动还是点击事件。
// 给滚动区域的父级加一个touchMove事件 onTouchMove() { this.isCenter = true this.clickIndex = -1 } 复制代码
通过touchMove事件通过isCenter来判断是否在滚动,如果在滚动将clickIndex置为-1,这样滚动的时候clickIndex为-1
// 判断isCenter是否在滚动否则返回-1 selectIndex() { if (this.isCenter) { return parseInt( (this.scrollLength + this.screenWidth / 2) / singleWidth ) } else { return -1 } }, 复制代码
经过上面的判断处理,clickIndex和scrollIndex就不会重复,不会出现两条高亮线的问题。
移除滚动事件
当数据列表宽度小于一个屏幕时或卸载页面的时候,我们需要移除监听事件,优化性能。
watch:{ 'chartList.length'(newLength) { if(newLength*singleWidth < this.screenWidth){ this.$refs.scroll.removeEventListener('scroll', this.scrollListenHandle) } } }, destroyed() { this.$refs.scroll.removeEventListener('scroll', this.scrollListenHandle) } 复制代码
小结
使用scroll-x:scroll实现滚动效果,通过this.$refs.scroll.removeEventListener('scroll',this.scrollListenHandle)来监听滚动的距离,通过计算得出高亮的柱子是哪条。通过点击事件改变this.$refs.scroll.scrollLeft的来实现动画的效果。
以上所述就是小编给大家介绍的《炫酷的运动柱状图统计动效》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- CVPR 2019 | 条件运动传播:从运动中学习物体性质
- 敏捷运动发起人马丁·福勒认为当前敏捷运动是一场悲剧
- 运动模糊滤镜
- 原生JavaScript之完美运动框架
- 运动App 自定义LocationMarker
- RMS 称开源运动是非道德的
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。