炫酷的柱状图滑动效果

要用到柱状图,第一时间想到去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的来实现动画的效果。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值