模拟滚动条

Author Avatar
Yoler|雷永亮 2月 28, 2017

最近由于需求原因,用vue做开发,自己动手模拟原生滚动条,做过之后觉得也没有那么难
点击观看Demo

下面直接贴出部分核心代码

   initscrollbar () {
      if (this.$refs.scroll_box.offsetHeight - this.$refs.page_content.offsetHeight <= 0) {
        this.rate = this.$refs.scroll_box.offsetHeight / this.$refs.page_content.offsetHeight
        this.scroll_bar_height = this.rate * this.$refs.scroll_box.offsetHeight - 4 + 'px'
        this.scroll_bar_top = -this.speed * this.rate + 2 + 'px'
        if (this.$refs.scroll_box.offsetHeight - this.$refs.page_content.offsetHeight >= this.speed) {
          this.speed = this.$refs.scroll_box.offsetHeight - this.$refs.page_content.offsetHeight
          this.page_content_top = this.speed + 'px'
          this.scroll_bar_top = -this.speed * this.rate + 2 + 'px'
        }
      } else {
        this.speed = 0
        this.page_content_top = this.speed + 'px'
        this.scroll_bar_height = 0
      }
    }

这一段代码是初始化滚动条的高度和位置,当窗口大小发生改变的时候通过容器高度和内容高度来计算出新的比率rate,再通过这个rate初始化滚动条的高度

   this.scroll_bar_height = this.rate * this.$refs.scroll_box.offsetHeight - 4 + 'px'
   scroll_bar_down (event) {
      this.disy = event.clientY
      document.addEventListener('mousemove', this.scroll_bar_move)
      document.addEventListener('mouseup', this.scroll_bar_up)
      this.curspeed = this.speed * this.rate
      this.mousestate = 1
    },
    scroll_bar_move (event) {
      document.body.style.cursor = 'default'
      let y = this.disy - event.clientY
      this.speed = (this.curspeed + y) / this.rate
      if (this.speed >= 0) {
        this.speed = 0
      }
      if (this.$refs.scroll_box.offsetHeight - this.$refs.page_content.offsetHeight >= this.speed) {
        this.speed = this.$refs.scroll_box.offsetHeight - this.$refs.page_content.offsetHeight
      }
      this.page_content_top = this.speed + 'px'
      this.scroll_bar_top = -this.speed * this.rate + 2 + 'px'
    },
    scroll_bar_up () {
      document.removeEventListener('mousemove', this.scroll_bar_move)
      this.mousestate = 0
    }

这一段代码是滚动条响应鼠标拖拽事件,当鼠标按下的时候记录此时的Y坐标,然后移动鼠标,计算移动距离。
注意: 滚动条移动的距离和鼠标移动的距离相等,而内容移动的距离要除以对应的比率,也就是rate

   scroll (event) {
      if (this.$refs.scroll_box.offsetHeight - this.$refs.page_content.offsetHeight <= 0) {
        if (event.wheelDelta === 120) {
          this.speed += 50
          if (this.speed >= 0) {
            this.speed = 0
          }
          this.page_content_top = this.speed + 'px'
          this.scroll_bar_top = -this.speed * this.rate + 2 + 'px'
        } else if (event.wheelDelta === -120) {
          this.speed -= 50
          if (this.$refs.scroll_box.offsetHeight - this.$refs.page_content.offsetHeight >= this.speed) {
            this.speed = this.$refs.scroll_box.offsetHeight - this.$refs.page_content.offsetHeight
          }
          this.page_content_top = this.speed + 'px'
          this.scroll_bar_top = -this.speed * this.rate + 2 + 'px'
        }
      }
    }

这段代码是滚动条响应鼠标滚动事件,当鼠标滚轮滚动一下,对应滚动条的移动距离,可自行设定。

下面贴出Html代码,仅供参考

   <div class="scroll_box" ref="scroll_box">
        <div class="page_content" :style="{top: page_content_top}" ref="page_content">
            <div class="page_item" v-for="(value, index) in pages">
                <div class="page_wrap" @click="page_seledt(index)" :class="{border: value.state}">
                    <div class="page_thumbnail"></div>
                    <div class="page_name">
                        <span>{{index}}</span>
                        <input type="text" v-model="value.name">
                    </div>
                    <div class="page_tool" v-show="value.state">
                        <div class="page_del"></div>
                        <div class="page_liked"></div>
                    </div>
                </div>
            </div>
        </div>
        <div class="warp_scroll_bar" v-show="scroll_bar_state"  ref="scroll_bar">
            <div class="scroll_bar" :style="{top: scroll_bar_top,height: scroll_bar_height}" :class="{ready:  mousestate}"></div>
        </div>
    </div>

如果大家有什么意见或建议,请在下方评论区留言