判断元素是否在视口内

element-is-in-view.js

export default class ElementIsInView {
  constructor(params) {
    if (!params.element) return;

    const {
      element,
      onViewTopHide,
      onViewBottomHide,
      onViewCenterShow,
      onViewTopIng,
      onViewBottomIng,
    } = params;
    this.element = element || '';
    this.onViewTopHide = onViewTopHide || null; // 在视口之上
    this.onViewBottomHide = onViewBottomHide || null; // 在视口之下
    this.onViewCenterShow = onViewCenterShow || null; // 在视口中间
    this.onViewTopIng = onViewTopIng || null; // 在视口上方出现或隐藏中
    this.onViewBottomIng = onViewBottomIng || null; // 在视口下方出现或隐藏中

    this.windowHeight = window.innerHeight
      || document.documentElement.clientHeight
      || document.body.clientHeight;

    this.listenerFunction = this.scrollEventListen.bind(this); // 用于销毁
    window.addEventListener('scroll', this.listenerFunction, true);
  }

  destroy() {
    window.removeEventListener('scroll', this.listenerFunction, true);
  }

  /**
   * @description: 获取元素宽高、距离视口上下左右的距离
   * @return {*}
   */
  getBoundingRect(element) {
    const rect = element.getBoundingClientRect();
    const top = document.documentElement.clientTop || 0;
    const left = document.documentElement.clientLeft || 0;
    return {
      top: rect.top - top,
      bottom: rect.bottom - top,
      left: rect.left - left,
      right: rect.right - left,
      width: rect.width,
      height: rect.height
    };
  }

  /**
   * @description: 滚动事件处理
   * @return {*}
   */
  scrollEventListen() {
    const elementBounding = this.getBoundingRect(this.element);
    const { top, bottom, height } = elementBounding;

    // 在视口之上
    if (bottom <= 0) {
      if (this.onViewTopHide && typeof this.onViewTopHide === 'function') {
        this.onViewTopHide();
      }
    }
    // 在视口之下
    if (top >= this.windowHeight) {
      if (this.onViewBottomHide && typeof this.onViewBottomHide === 'function') {
        this.onViewBottomHide();
      }
    }
    // 正在视口中
    if (top > 0 && top < this.windowHeight && bottom > 0 && bottom < this.windowHeight) {
      if (this.onViewCenterShow && typeof this.onViewCenterShow === 'function') {
        this.onViewCenterShow();
      }
    }
    // 在视口上方出现或隐藏中
    if (top <= 0 && bottom <= height && bottom > 0) {
      if (this.onViewTopIng && typeof this.onViewTopIng === 'function') {
        this.onViewTopIng();
      }
    }
    // 在视口下方出现或隐藏中
    if (top < this.windowHeight && bottom >= this.windowHeight) {
      if (this.onViewBottomIng && typeof this.onViewBottomIng === 'function') {
        this.onViewBottomIng();
      }
    }
  }

  /**
   * @description: 此刻元素在视口中的位置状态
   * @return {*} top-hide | bottom-hide | center-show| top-ing | bottom-ing
   */
  elementInViewStatus() {
    const elementBounding = this.getBoundingRect(this.element);
    const { top, bottom, height } = elementBounding;

    // 在视口之上
    if (bottom <= 0) return 'top-hide';
    // 在视口之下
    if (top >= this.windowHeight) return 'bottom-hide';
    // 正在视口中
    if (top > 0 && top < this.windowHeight && bottom > 0 && bottom < this.windowHeight)  return 'center-show';
    // 在视口上方出现或隐藏中
    if (top <= 0 && bottom <= height && bottom > 0) return 'top-ing';
    // 在视口下方出现或隐藏中
    if (top < this.windowHeight && bottom >= this.windowHeight)  return 'bottom-ing';
  }
}

demo

import ElementIsInView from 'element-is-in-view';
const eleIsInView = new ElementIsInView({
   element: document.querySelector('#banner'),
   onViewTopHide: () => {},
   onViewBottomHide: () => {},
   onViewTopIng: () => {},
   onViewBottomIng: () => {},
   onViewCenterShow: () => {}
});
const curStatus = eleIsInView.elementInViewStatus();
eleIsInView.destroy();