美文网首页
项目中关于监听和移除scroll的坑

项目中关于监听和移除scroll的坑

作者: 撑船的摆渡人 | 来源:发表于2020-01-14 16:15 被阅读0次

项目背景:当进入页面滚动的时候,页面中的元素出现在视野的时候,展示一下动画效果。
技术栈:vue
实现方法:主要是给需要动画的元素添加animation+X/Y/L/R class样式

解决什么问题:

  1. 网上的好多滚动事件没有添加防抖函数,这样会导致在滚动过程中会有白屏现象。
  2. 另外就是没有移除事件监听,在离开当前页面的时候,需要在销毁组件之前移除滚动事件,否则跳转路由之后,事件仍然会被调用,浪费资源
  3. 为什么不直接 window.addEventListener('scroll', throttle(this.handleScroll, 0, 500))这样写?因为我发现这样在remove的时候移除不了。所以监听处理写个声明式函数、或者用函数表达式赋值给变量比较好些,这样移除事件监听方便些。

开始吧

/**
 * 在 mounted() 的时候(el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。)
 * 添加事件监听 
 */
    this.throttleLoad = throttle(this.handleScroll, 0, 500)
    window.addEventListener('scroll', this.throttleLoad)
    this.handleScroll() // 并首次调用动画(可能有些元素在不同尺寸的屏幕下,有可能需要执行动画)

methods 中监听调用的方法

  // 不同页面调用不同的方法
    handleScroll(e) {
      const clientH = window.innerHeight
      const boxListL = [...document.querySelectorAll('.animationL')]
      boxListL.forEach((item, index) => {
        const Rect = item.getBoundingClientRect()
        if (Rect.top + 130 < clientH) {
          handleAddClass(item, 'animation-activeL')
        } else {
          handleRemoveClass(item, 'animation-activeL')
        }
      })
      const boxListR = [...document.querySelectorAll('.animationR')]
      boxListR.forEach((item, index) => {
        const Rect = item.getBoundingClientRect()
        if (Rect.top + 130 < clientH) {
          handleAddClass(item, 'animation-activeR')
        } else {
          handleRemoveClass(item, 'animation-activeR')
        }
      })
    }
  }

主动销毁

  beforeDestroy() {
    window.removeEventListener('scroll', this.throttleLoad)
  }

公共的方法抽离出来放到公共js中

// 因为当时考虑到兼容问题,在IE低版本中没有classList.add / remove 这些方法
/**
 * Add class
 * @param {DOM} item
 * @param {className} name
 */
export function handleAddClass(item, name) {
  if (item.classList) {
    item.classList.add(name)
  } else {
    const classes = item.className.split(/\s+/g)
    if (classes.indexOf(name) < 0) {
      classes.push(name)
    }
    item.className = classes.join(' ')
  }
}
/**
 * Remove class
 * @param {DOM} item
 * @param {className} name
 */
export function handleRemoveClass(item, name) {
  if (item.classList) {
    item.classList.remove(name)
  } else {
    const classes = item.className.split(/\s+/g)
    const n = classes.indexOf('animation-activeL')
    if (n > -1) {
      classes.splice(n, 1)
    }
    item.className = classes.join(' ')
  }
}
/**
 * 防抖
 * @param fn 执行的函数
 * @param delay 延时时间
 * @param atleast 达到强制执行的条件
 */
export function throttle(fn, delay, atleast) {
  let timer = null
  let previous = null
  return function () {
    const now = +new Date()
    if (!previous) previous = now
    if (atleast && now - previous > atleast) {
      fn()
      previous = now
      clearTimeout(timer)
    } else {
      clearTimeout(timer)
      timer = setTimeout(function () {
        fn()
        previous = null
      }, delay)
    }
  }
}

相关文章

网友评论

      本文标题:项目中关于监听和移除scroll的坑

      本文链接:https://www.haomeiwen.com/subject/kfzzmctx.html