首頁 web前端 js教程 javascript實作瀑布流載入圖片原理_javascript技巧

javascript實作瀑布流載入圖片原理_javascript技巧

May 16, 2016 pm 03:16 PM

講一下大概的原理吧,還是先上圖:

 

 功能描述:

  • 根據不同選單的屬性值分別載入不同的資料
  • 下拉捲軸到一定位置預先載入圖片,捲動條拉到最底下的時候渲染html;
  • 滑鼠移到選單,切換各個圖片清單;
  • 滑鼠移到圖片清單上,顯示詳細資料; 

技術實作方案:

  先梳理一下從載入到顯示的流程:
  1. 載入資料
  2. 拼接HTML寫入到頁面
  3. 檢查剛寫入的HTML中的img是否全部載入完成,如果是,進入5、否則進入4
  4. 等待圖片載入完成
  5. 計算每個元素的位置

  一開始的時候最頭疼的是如何定位的問題,後來經過朋友指導終於解決:計算總共有多少列圖片並且把每一列的高度都放到一個數組裡面。每當一張圖片載入完成的時候就找出這個陣列裡面最小的值,並且定位目前圖片的top設定為這個值,完成後把這個圖片的高度加上陣列裡面的最小值並且回到陣列裡面,依次類推。 
 PS:因為這個功能代碼太多,只能作基本的簡單分解程式碼了: 

// 创建用于记录每列高度的数组
_getLowestCol: function() {
  t._cols = new Array(5),min = 0;
  // 初始化为0
  for (var i = 0; i < t._cols.length; i++) {
    if (cols[i] < cols[min]) {
      min = i;
    }
    return min;
  }
},
_reposition: function() {
  t._grids.each(function(i, grid) {
    //先显示出来
    grid = $(grid).show();
    
    var height = grid.outerHeight(), min = t._getLowestCol();

    // 定位
    grid.animate({
      left: (t._colWidth + t._colSpacing) * min,
      top: t._cols[min],
      opacity: 1
    },1000);
    // 记录高度
    t._cols[min] += height;
  });

}

登入後複製

 其次開發過程中遇到的難題是:因為如上圖所示,滑鼠移動到選單欄需要切換圖片列表,並且分別需要用瀑布流載入不同類型的資料。所以要處理在切換頁面的時候如何才能做到每個頁面只執行一次代碼請求接口,而不需要每一次切換都重新請求數據接口,僅僅執行切換顯示圖片列表的操作就可以了。
  考慮到每個選單都有一個自訂屬性,所以這個問題輕易地解決了:建立一個物件來記錄目前選單是否已經執行過程式碼,如果沒有就執行請求資料 。 

var isLoad = {};//是否载入过
labelType.mouseover(function() {
  var i = $(this).index();
  var api = _this.attr('api');//接口标识
  
  if(! isLoad[ api ]){
    isLoad[ api ] = i;
    loadData(wrapper, api);
  }
  
});
登入後複製

以下為全部程式碼:
html:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<style type="text/css">
*{margin:0;padding:0;}
ul,li{  list-style-type:none;}
li img{width:100%;list-style:none;}
</style>
</head>
<body>
  <div class="photo_box">
    <ul id="container" style="border:1px solid #000;width:80%;height:600px;overflow:hidden;margin:0 auto;position: relative;">
    </ul>
    <div id="loading" class="loading" style="text-align: center;margin-top: 20px;font-size: 1.2em;">加载中...</div>
    <div id="more" class="more"style="text-align: center;margin-top: 20px;font-size: 1.2em;"><input type="button" value="更 多" id="clear" /></div>
  </div>
<script type="text/javascript" src="../../lib/seajs/sea.js"></script>
<script type="text/javascript" src="../../lib/base/1.0.x/base.js"></script>
<script type="text/javascript">
seajs.use(['lib/jquery/1.11.x/index.js', '_example/waterFall_1.1/waterfall.js'], function($, waterFall) {
  waterFall.init({
    container: $('#container'),
    dataURL: 'http://www.woxiu.com/index.php&#63;action=Index/Main&do=ApiZhuboGrade',
    dataType: 'jsonp',
    template: '<% for (var i = 0; i < data.length; i++) { %>' +
            '<li style="display: none;">' +
              '<img src=" <%-data[i].room_img%> ">' +
            '</li>' + 
          '<% } %>',
    colWidth: 200,
    colSpacing: 10,
    rowSpacing: 15,
    page: 1,
    pageEnd: 8,
  });

  // 限制同时展示的页数
  var loadCounter = 1;
  function pageNum(){
    if (loadCounter >= 3) {
      $('#more').show();
      $('#loading').hide();
      return true;
    } else {
      loadCounter++;
      $('#more').hide();
      $('#loading').show();
    }
    return false;
  }
  $('#clear').click(function() {
    loadCounter = 1;
    waterFall._loadNext();
  });
});

</script>
</body>

登入後複製

js:

/**
 * 瀑布流布局组件类
 * @param {Object} options 组件设置
 *    @param {NodeList} options.container 瀑布流容器
 *    @param {String} options.dataURL 数据地址
 *    @param {String} [options.dataType='jsonp'] 数据类型,json或jsonp
 *    @param {String}  options.template 模板编辑
 *    @param {Number} [options.colWidth] 图片大小。
 *    @param {Number} [options.colSpacing] 列间隔。
 *    @param {Number} [options.rowSpacing] 行间隔。
 *    @param {Number} [options.page=1] 数据开始页码
 *    @param {Number} [options.pageEnd] 数据末尾页码

 * @pageNum() 函数,如果不需要现在加载也是,需要把函数里面的判断去掉。


 从加载到显示的流程

1. 加载数据
2. 拼接HTML写入到页面
3. 检查刚刚写入的HTML中的img是否全部加载完成,如果是,进入5、否则进入4
4. 等待图片加载完成
5. 计算每个元素的位置

 */
define(function(require, exports, module) {
  'use strict';
  
  var Tmpl = require('lib/tmpl/2.1.x/index.js'),
    $ = require('lib/jquery/1.11.x/index.js');

  var waterFall = {
    init: function(options) {
      var t = this;
      t._container = options.container;
      t._template = options.template;
      t._colWidth = options.colWidth;
      t._colSpacing = options.colSpacing;
      t._rowSpacing = options.rowSpacing;
      t.dataURL = options.dataURL;
      t.dataType = options.dataType;
      t.page = options.page;
      t.pageEnd = options.pageEnd;
      t._switch = false;

      //计算有几列 总宽度 / (列宽 + 列间隔)
      t._totalCols = parseInt(t._container.width() / (t._colWidth + t._colSpacing));

      // 创建用于记录每列高度的数组
      t._cols = new Array(t._totalCols);
      // 初始化为0
      for (var i = 0; i < t._cols.length; i++) {
        t._cols[i] = 0;
      }

      t._loadingPage = options.page || 0;
      t._loadNext(options);

      //下拉滚动条加载
      var lastTime = new Date().getTime();

      $(window).scroll(function() {

        if ( !t._switch ) {
          //判断是否滚动过快,在ie下
          var thisTime = new Date().getTime();

          if (thisTime - lastTime < 50) {
            console.log(thisTime - lastTime);
            lastTime = thisTime;
            return;
          }

          if ($(window).scrollTop() + $(window).height() >= document.documentElement.scrollHeight) {
            lastTime = thisTime;
            t._loadNext();
          }
        }
      });
    },
    //加载器
    _loadNext: function(t) {
      var t = this;

      t._switch = true;
      //请求数据
      if (!t.trigger) {
        $.ajax({
          url: t.dataURL,
          data: { page: ++t._loadingPage },
          dataType:t.dataType,
          success: function(response){
            
            t.trigger = t._completeLoading(response);

          },
          error:function(){console.log('Error! 请求有误');}
        });  
      }
      return false;
    },
    //加载完数据调用此函数
    _completeLoading: function(result) {
      var t = this;
      if (t._loadingPage >= t.pageEnd) {
        $('#more').hide();
        $('#loading').html('<p>已是最后一页了喔 ^_^ ^_^</p>');
        return true;
      }
      else {
        //if (!pageNum()) {
          t._add(result);
        //};
      }
      
      return false;
    },
    //添加格子
    _add: function(result) {
      var t = this, grids = '';
      //调用模板
      var content = Tmpl.render(t._template, {data:result.data});
      //原始定位
        t._grids = $(content).css({
          position: 'absolute',
          left: t._container.width(),
          top: t._container.height(), 
          width: t._colWidth,
          opacity: 0
        });

      //把Html添加到容器
      t._container.append(t._grids);

      // 执行一次_reposition,如果所有图片都加载完成,该方法返回true,否则返回false
      if ( !t._reposition() ) {
        // 有图片未加载完,监听onload和onerror
        t._grids.find('img').bind('load error', function() {
          this.loaded = true;
          // 有图片加载完成,再次执行_reposition
          if (t._grids) {
            t._reposition();
          }
        });
      }
    },
    // 此方法用于获取高度最低的列
    _getLowestCol: function() {
      var cols = this._cols, min = 0;
      for (var i = 1; i < cols.length; i++) {
        if (cols[i] < cols[min]) {
          min = i;
        }
      }
      return min;
    },
    //定位
    _reposition: function() {

      var t = this, allImgsLoaded = true;

      // 检测图片是否全部加载完成
      t._grids.find('img').each(function(i, img) {
        if (!img.loaded && !img.complete) {

          allImgsLoaded = false;
        }
        return allImgsLoaded;
      });

      if (allImgsLoaded) {
        t._grids.each(function(i, grid) {
          //先显示出来
          grid = $(grid).show();
          
          var height = grid.outerHeight(), min = t._getLowestCol();

          // 非第一行的时候,要加上行间隔
          if (t._cols[min]) { t._cols[min] += t._rowSpacing; }
          // 定位
          grid.animate({
            left: (t._colWidth + t._colSpacing) * min,
            top: t._cols[min],
            opacity: 1
          },1000);
          // 记录高度
          t._cols[min] += height;
        });
        // 重设外层容器高度为最高列高度
        t._container.css( 'height', Math.max.apply(Math, t._cols) );
        t._switch = false;
        delete t._grids;
      }

      return allImgsLoaded;
    },
  }

  return waterFall;
});
登入後複製

以上就是本文的全部內容,希望對大家學習javascript程式設計有所幫助。

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

前端熱敏紙小票打印遇到亂碼問題怎麼辦? 前端熱敏紙小票打印遇到亂碼問題怎麼辦? Apr 04, 2025 pm 02:42 PM

前端熱敏紙小票打印的常見問題與解決方案在前端開發中,小票打印是一個常見的需求。然而,很多開發者在實...

神秘的JavaScript:它的作用以及為什麼重要 神秘的JavaScript:它的作用以及為什麼重要 Apr 09, 2025 am 12:07 AM

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

誰得到更多的Python或JavaScript? 誰得到更多的Python或JavaScript? Apr 04, 2025 am 12:09 AM

Python和JavaScript開發者的薪資沒有絕對的高低,具體取決於技能和行業需求。 1.Python在數據科學和機器學習領域可能薪資更高。 2.JavaScript在前端和全棧開發中需求大,薪資也可觀。 3.影響因素包括經驗、地理位置、公司規模和特定技能。

如何使用JavaScript將具有相同ID的數組元素合併到一個對像中? 如何使用JavaScript將具有相同ID的數組元素合併到一個對像中? Apr 04, 2025 pm 05:09 PM

如何在JavaScript中將具有相同ID的數組元素合併到一個對像中?在處理數據時,我們常常會遇到需要將具有相同ID�...

JavaScript難以學習嗎? JavaScript難以學習嗎? Apr 03, 2025 am 12:20 AM

學習JavaScript不難,但有挑戰。 1)理解基礎概念如變量、數據類型、函數等。 2)掌握異步編程,通過事件循環實現。 3)使用DOM操作和Promise處理異步請求。 4)避免常見錯誤,使用調試技巧。 5)優化性能,遵循最佳實踐。

如何實現視差滾動和元素動畫效果,像資生堂官網那樣?
或者:
怎樣才能像資生堂官網一樣,實現頁面滾動伴隨的動畫效果? 如何實現視差滾動和元素動畫效果,像資生堂官網那樣? 或者: 怎樣才能像資生堂官網一樣,實現頁面滾動伴隨的動畫效果? Apr 04, 2025 pm 05:36 PM

實現視差滾動和元素動畫效果的探討本文將探討如何實現類似資生堂官網(https://www.shiseido.co.jp/sb/wonderland/)中�...

JavaScript的演變:當前的趨勢和未來前景 JavaScript的演變:當前的趨勢和未來前景 Apr 10, 2025 am 09:33 AM

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

console.log輸出結果差異:兩次調用為何不同? console.log輸出結果差異:兩次調用為何不同? Apr 04, 2025 pm 05:12 PM

深入探討console.log輸出差異的根源本文將分析一段代碼中console.log函數輸出結果的差異,並解釋其背後的原因。 �...

See all articles