Vue2-自定义指令-元素滚动到指定位置

Vue2-自定义指令-元素滚动到指定位置

前言

没有前言。

功能

利用vue全局自定义指令 写了一个让元素上下滚动指定偏移量功能。

自定义指令 ‘scroll-top’

自定义指令模块TickDirective.js代码如下:

import Vue from 'vue'

//全局自定义指令  给目标元素动画滚动到指定偏移位置 如果绑定值为true 则滚动到顶部
Vue.directive('scroll-top', {
  /**
   * 
   * @param {object} el 
   * @param {object} binding 
   * binding.value={
   *        allowScroll:false,是否允许滚动
   *        offset:0,滚动到距父元素上偏移量
   *        complete:()=>{},滚动结束的回调,用来初始化/还原绑定值
   * }
   */
  componentUpdated: function (el, binding, ) {
    //是否允许滚动
    let allowScroll = false
    //目标偏移
    let goalOffset = 0
    //动画完成的回调
    let completeCall = null
    //速度因子
    let divisor = 5

    //如果绑定值是boolean类型 默认滚动到顶部
    if (typeof binding.value == "boolean") {
      allowScroll = binding.value
    }
    //如果绑定值是对象类型 
    if (binding.value && typeof binding.value == "object") {
      allowScroll = binding.value.allowScroll || false
      goalOffset = binding.value.offset || 0
      completeCall = binding.value.complete
      divisor = binding.value.divisor || 5
    }

    //获取html原生元素
    const element = el.$el ? el.$el : el

    //滚动逻辑
    if (allowScroll == true) {
      //如果偏移量 和目标偏移量相等 则不滚动 并执行回调方法
      if (element.scrollTop == goalOffset) {
        if (completeCall) {
          //回调函数里记得把绑定值初始化 比如设为false
          completeCall()
        }
        return
      }

      //判断滚动方向 
      let direction = 'up'
      //目标偏移 大于当前偏移 需向上滚动 增加元素上偏移
      if (goalOffset > element.scrollTop) {
        //向上 
        direction = 'up'
      } else {
        //向下
        direction = 'down'
      }

      //获取当前偏移和目标偏移的绝对差值
      let offsetDiff = Math.abs(goalOffset - element.scrollTop)

      //计时器 滚动逻辑
      let timer = setInterval(() => {
        //计算速度  向上舍入 速度最小为 1 这样element.scrollTop == goalOffset 最后必然成立
        //注意 当offsetDiff小于divisor后 速度将恒为1 所以 divisor不不宜过大 建议设为5
        let ispeed = Math.ceil(offsetDiff / divisor)

        //计算剩余差值
        offsetDiff = offsetDiff - ispeed

        //根据滚动方向 判断偏移量是加是减
        if (direction == 'up') {
          element.scrollTop = element.scrollTop + ispeed
        } else {
          element.scrollTop = element.scrollTop - ispeed
        }

        //当前偏移 等于目标偏移 停止滚动 清除计时器 并执行回调方法
        if (element.scrollTop == goalOffset) {
          clearInterval(timer)
          if (completeCall) {
            //回调函数里记得把绑定值初始化 比如设为false
            completeCall()
          }
        }
      }, 16)
    }
  }
})

代码有点多 主要是判断逻辑上。

引用

main.js 中 引入:

//使自定义全局指令生效
import '@/utils/TickDirective.js'

使用

在这里插入图片描述
其中 .install-row-class是要有css属性overflow的元素
在这里插入图片描述

data

data() {
    return {
      scrollTop: false,
    }

这样 每次给scrollTop赋值时 都会执行指令里的逻辑。
需要注意的是: 组件创建时 会执行一次指令逻辑, 所以这里把scrollTop初始化为false。因此,要注意对scrollTop的复原,代码中添加的completeCall支持回调,用于binding.value为对象时自行添加复原代码。

复原代码

我的实际应用代码中 子组件调用 祖先组件提供的provide,使祖先组件滚动。
祖先代码:

  provide() {
    return {
      updateScrollTop:(offset)=> {
        this.scrollTop = {
          allowScroll: true,
          offset,
          complete: ()=> {
            this.scrollTop = false
          }
        }
      }
    }
  },

子孙代码:

  inject: ['updateScrollTop'],

  methods: {
	scrollOffset(){
	  //目标元素 偏移量
	  this.updateScrollTop(this.$refs.baseProInfo.$el.offsetTop)
	}
  }

最后

实际效果:
在这里插入图片描述
参考文档:
JS中offsetTop、clientTop、scrollTop、offsetTop各位置属性详解

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过自定义指令来实现点击标签滚动到页面相应位置,以及页面滚动对应标签高亮功能。以下是实现方法: 1. 点击标签滚动到页面相应位置 先创建一个自定义指令`scroll-to`,并在指令中绑定点击事件,通过`window.scrollTo()`方法实现滚动到相应位置。 ``` <template> <div> <ul> <li v-for="(item, index) in list" :key="index" v-scroll-to="index"> {{ item }} </li> </ul> <div v-for="(item, index) in list" :key="index" ref="element">{{ item }}</div> </div> </template> <script> export default { data() { return { list: ['A', 'B', 'C', 'D'] } }, directives: { scrollTo: { inserted(el, binding) { el.addEventListener('click', () => { const index = binding.value const element = el.$parent.$refs.element[index] window.scrollTo({ top: element.offsetTop, behavior: 'smooth' }) }) } } } } </script> ``` 2. 页面滚动对应标签高亮功能 同样是在自定义指令中监听浏览器的滚动事件,在滚动时判断当前滚动位置对应哪个标签,并设置该标签的高亮样式。 ``` <template> <div> <ul> <li v-for="(item, index) in list" :key="index" v-scroll-to="index" :class="{ 'active': activeIndex === index }"> {{ item }} </li> </ul> <div v-for="(item, index) in list" :key="index" ref="element">{{ item }}</div> </div> </template> <script> export default { data() { return { list: ['A', 'B', 'C', 'D'], activeIndex: 0 } }, directives: { scrollTo: { inserted(el, binding) { el.addEventListener('click', () => { const index = binding.value const element = el.$parent.$refs.element[index] window.scrollTo({ top: element.offsetTop, behavior: 'smooth' }) }) } } }, mounted() { window.addEventListener('scroll', this.handleScroll) }, beforeDestroy() { window.removeEventListener('scroll', this.handleScroll) }, methods: { handleScroll() { const scrollTop = document.documentElement.scrollTop || document.body.scrollTop for (let i = 0; i < this.list.length; i++) { const element = this.$refs.element[i] if (scrollTop >= element.offsetTop && scrollTop < element.offsetTop + element.offsetHeight) { this.activeIndex = i break } } } } } </script> <style> .active { color: red; } </style> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值