可視化範圍加載複習

 1、定義監聽函數,監聽onscroll事件

 2、提前佔位,並且能獲取每個模塊的高度

 3、判斷是否在可視範圍內,如果在,則加載

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
  <style type="text/css">
    body{
      height: 937px;
      margin: 0px;
    }
  </style>
</head>
<body>
  <h2 id="title">可視範圍加載</h2>
  <div id="main"></div>
  <script>
    <!-- 模擬模塊 定義高度-->
    class module {
      setContent(content) {
        this.content = content;
      }
      content;
      create() {
        return `<div id="content_${this.content}" style="height: ${this.height}px;border: 1px solid red;">${this.content}</div>`
      }
      height = 500;
      getHeight() {
        return this.height;
      }
    }

    window.onload = function(){
      const moduleArr = [];
      const moduleStrArr = [];
      for (let i = 0; i < 100; i++) {
        const _module = new module(i);
        _module.setContent(i);
        moduleStrArr.push(_module.create());
        moduleArr.push(_module)
      }
      const div = document.getElementById('main');
      div.innerHTML = moduleStrArr.join('');
      document.body.appendChild(div);

    };
    // 滾動
    window.onscroll = debounce(()=>{
      for (let i = 0; i < 100; i++) {
        if (isVisible(document.getElementById('content_'+i))) {
          console.log(i);
          // 下發處理
        }
      }
    }, 200);

    /**
     * 防抖  第一次不會立即執行
     * @date 2019/12/6
     */
    /**
     * @desc 函數防抖
     * @param fn 函數
     * @param timeout 延遲執行毫秒數
     * @param immediate true 表立即執行,false 表非立即執行
     */
    function debounce(fn, timeout, immediate) {
      let _timeout;
      return function () {
        let context = this;
        let args = arguments;

        if (_timeout) clearTimeout(_timeout);
        if (immediate) {
          let callNow = !_timeout;
          _timeout = setTimeout(() => {
            _timeout = null;
          }, timeout);
          if (callNow) fn.apply(context, args)
        } else {
          _timeout = setTimeout(function(){
            fn.apply(context, args)
          }, timeout);
        }
      }
    }

    /**
     * @desc 函數節流
     * @param fn 函數
     * @param timeout 延遲執行毫秒數
     * @param type 1 表時間戳版,2 表定時器版
     */
    function throttle(fn, timeout ,type) {
      let previous = 0;
      let _timeout;

      return function() {
        let context = this;
        let args = arguments;
        if(type===1){
          let now = Date.now();

          if (now - previous > timeout) {
            fn.apply(context, args);
            previous = now;
          }
        }else if(type===2){
          if (!_timeout) {
            _timeout = setTimeout(() => {
              _timeout = null;
              fn.apply(context, args)
            }, timeout)
          }
        }
      }
    }

    /**
     * @函數名稱:
     * @作用:判斷是否在可視範圍內 目前只處理高度
     * @date 2019/12/6
     */
    function isVisible(el) {
      const _el = el ? getElementPosition(el) : '';
      if (_el) {
        const windowSize = getWindowSize();
        // clientHeight 元素的可視高度,內部滾動,border margin不會計算 padding會計算
        // _el.top offsetTop  元素距離上方或者上層控件的位置
        // pageYOffset 元素在窗口左上角水平和垂直方向滾動的像素。
        // availHeight 窗口的可視高度
        // _el.top + el.clientHeight > window.pageYOffset 元素的上偏移值+元素的內部高度>瀏覽器窗口豎直方向滑動值  上面滾入
        // window.pageYOffset + windowSize.availHeight> _el.top 瀏覽器窗口豎直方向滑動值+瀏覽器視口高度>元素的上偏移值 下面滾出
        return _el.top + el.clientHeight > window.pageYOffset && window.pageYOffset + windowSize.availHeight > _el.top;
      }
      return false;
    }

    /**
     * @函數名稱:
     * @param
     * @作用:獲取元素的左邊和上邊的位置
     * @date 2019/12/6
     */
    function getElementPosition(obj) {
      var top = 0;
      var left = 0;

      while(obj){
        top += obj.offsetTop;
        left += obj.offsetLeft;

        obj = obj.offsetParent;
      }
      return {top,left};
    }


    /**
     *
     * @returns {
     * {width: *, height: *, 內容寬高
     * availWidth: *, availHeight: 可視寬高
     * *, screenHeight: Number, screenWidth: Number 分辨率寬高
     * }}
     */
    function getWindowSize() {
      let xScroll;
      let yScroll;
      let pageWidth;
      let pageHeight;
      if (window.innerHeight && window['scrollMaxY']) {
        xScroll = window.innerWidth + window['scrollMaxX'];
        yScroll = window.innerHeight + window['scrollMaxY'];
      } else {
        if (document.body.scrollHeight > document.body.offsetHeight) {
          // all but Explorer Mac
          xScroll = document.body.scrollWidth;
          yScroll = document.body.scrollHeight;
        } else {
          // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
          xScroll = document.body.offsetWidth;
          yScroll = document.body.offsetHeight;
        }
      }
      let windowWidth, windowHeight;
      if (self.innerHeight) {
        // all except Explorer
        if (document.documentElement.clientWidth) {
          windowWidth = document.documentElement.clientWidth;
        } else {
          windowWidth = self.innerWidth;
        }
        windowHeight = self.innerHeight;
      } else {
        if (document.documentElement && document.documentElement.clientHeight) {
          // Explorer 6 Strict Mode
          windowWidth = document.documentElement.clientWidth;
          windowHeight = document.documentElement.clientHeight;
        } else {
          if (document.body) {
            // other Explorers
            windowWidth = document.body.clientWidth;
            windowHeight = document.body.clientHeight;
          }
        }
      }
      // for small pages with total height less then height of the viewport
      if (yScroll < windowHeight) {
        pageHeight = windowHeight;
      } else {
        pageHeight = yScroll;
      }
      // for small pages with total width less then width of the viewport
      if (xScroll < windowWidth) {
        pageWidth = xScroll;
      } else {
        pageWidth = windowWidth;
      }
      return {
        width: pageWidth,
        height: pageHeight,
        availWidth: windowWidth,
        availHeight: windowHeight,
        screenHeight: window.screen.height,
        screenWidth: window.screen.width,
      };
    }
  </script>
</body>
</html>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章