基于element-ui el-scrollbar 自定义滚动指令

不怎么擅长写文档,先上效果图 

github源码地址 

背景: 在使用element-ui 开发项目中,有一个隐藏的组件 el-scrollbar 可以用来美化滚动条,往往有这种需求,需要滚动到一定的位置,并且可以加一些过渡的动画,为此写了一个组件和大家分享一下。

思路:

  1. vue 自定义指令
  2. scrollHeight/clientHeight/scrollTop 等dom上的属性 用于偏移量的计算
  3. window.requestAnimateframe 动画 不平滑

代码:

import Vue from 'vue'

/**
 * description: el-scrollbar 滚动条滚动指令
 * directive-name: roll
 * @param el: 指令所绑定的元素,可以用来直接操作 DOM
 * @param distance 偏移距离 px/number 注:0 顶部 -1 底部,其余按照实际值,超过边界滚到底部
 * @param time 过渡时间 ms/number
 * @param flag 是否开启滚动 boolean
 */
Vue.directive('roll', function (el, { arg: { distance, time, flag } }) {
  if (
    distance !== null &&
    time !== null &&
    flag
  ) {
    const wrap = el.querySelector('.el-scrollbar__wrap')
    // 滚动条最大偏移距离
    const maxDistance = wrap.scrollHeight - wrap.clientHeight
    // 处理边界
    distance = (distance < 0 || distance > maxDistance) ? maxDistance : distance
    // 每帧需要偏移的距离 默认60fps/s 偏移量向上取整
    const _distance = Math.ceil(Math.abs(wrap.scrollTop - distance) * 1000 / time / 60)
    // 初始偏移量
    const initScrollTop = wrap.scrollTop
    // 执行动画
    const keyframe = () => {
      if (initScrollTop - distance > 0) wrap.scrollTop -= _distance
      else wrap.scrollTop = wrap.scrollTop + _distance
      // 判断中止条件
      if (Math.abs(wrap.scrollTop - distance) > _distance) requestAnimationFrame(keyframe)
      else wrap.scrollTop = distance
    }
    keyframe()
  }
})

测试demo

<template>
  <div class="test">
    <el-row>
      <el-col :span="8">
        <el-input v-model="distance" placeholder="偏移距离">
          <template slot="append">px</template>
        </el-input>
      </el-col>
      <el-col :span="8">
        <el-input v-model="time" placeholder="滚动时间">
          <template slot="append">ms</template>
        </el-input>
      </el-col>
      <el-col :span="8">
        <el-button type="primary" @click="scroll">开始滚动</el-button>
        <el-button type="primary" @click="addCount">增加行数</el-button>
      </el-col>
    </el-row>
    <div style="margin-top: 20px; height: 300px;">
      <el-scrollbar
          ref="scrollbar"
          v-roll:[scrollData]="scrollData"
          style="height: 100%; background: #ffffff;"
          wrap-style="overflow-x: hidden;"
      >
        <ul>
          <li
              v-for="item in rowCount"
              :key="item"
          >{{ item }}你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好</li>
        </ul>
      </el-scrollbar>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'Test',
    data () {
      return {
        rowCount: 30,
        distance: null,
        time: null,
        // 滚动条支持事件
        scrollData: {
          distance: null, // 滚动距离
          time: null, // 动画时间
          flag: false, // 是否开启滚动
        },
      }
    },
    methods: {
      scroll () {
        const distance = Number(this.distance) || 0
        const time = Number(this.time) || 0
        this.scrollData = {
          flag: true,
          distance: distance,
          time: time
        }
      },
      async addCount () {
        this.scrollData.flag = false
        await this.$nextTick()
        this.rowCount++
      },
    },
  }
</script>

<style>
html,body {
  background: rgb(247, 247, 247);
}
.test {
  width: 50%;
  margin: 0 auto;
}
</style>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值