木桶佈局,瞭解一下

引言

最近公司有個項目要用到木桶佈局,找了不少插件都感受不合適,因而決定本身擼一個。已經開源到github。(文章寫的匆忙,有錯別字或bug請指正)css

什麼是木桶佈局,咱們隨便百度一張圖片就知道了。以下圖。 git

那麼問題來了,要怎麼實現這種效果呢?本人想了一種思路,看下圖。

首先排列若干圖片,用一個基準高度來設置他們,讓後當放不下的時候在進行總體縮放。github

實現

讓咱們愉快的coding吧~,準備把它封裝成一個jQ插件。考慮設計如下方法bash

  • loader 圖片加載器
  • render 圖片渲染器
  • template 模板渲染器
  • resize 從新排版器
  • loadMore 動態加載圖片

那麼讓咱們建立iboot.js。app

;(function ($, root) {
    
    function Iboot() {
        
    }
    
})(jQuery, window);
複製代碼

這樣實現了一個簡單的jq插件模板。因爲某些參數須要傳遞過來,咱們要繼續完善。dom

function Iboot(ele, config) {
    
    this.ele = $(ele)
    this.eleWidth = this.ele.width()
    
    this.config = $.extend({ // 這裏會合併用戶傳來的參數
      baseHeight: 400, // 默認基準高度
      list: [ // 定義圖片格式
        {
          src: '',
          alt: 'xxx'
        }
      ],
      template: function (dom) {
        return dom
      },
      scrollBox: $(document.body),
  
      afterLoad: function () { //加載以前回調
      
      },
  
      beforeLoad: function () { //加載以後回調
      
      }
    }, config)
  
    this.innerData = { //內置的儲存器
      nowItemWidth: 0, //如今的增長長度
      appendDoms: [],
      scrollBoxData: {
      
      },
      saveDom: [],
      groupid: 0
    }
  }

複製代碼

實現圖片加載器

首先咱們要實現圖片加載器,代碼以下。ide

Iboot.prototype.loader = function(list, success, error, done){
    var now = 0;
    $.each(list, function (i, v) {
      (function (i, v) {
        var img = new Image()
        img.onload = function () {
          success(v, img)
          now++
          if(now === list.length) {
            done()
          }
        }
        img.onerror = function (err) {
          error(v, img, err)
          now++
          if(now === list.length) {
            done()
          }
        }
        img.src = v.src
        img.alt = v.alt
      })(i, v);
    })
  }
複製代碼

加載傳入的list,加載後分別指派給回調函數 success(成功以後)error(加載失敗)done(所有加載完成)函數

實現模板函數

Iboot.prototype.template = function(src, alt){
    var item = $('<div class="iboot-item" style="float: left"></div>');
    item.append(
      $('<img src="'+src+'" alt="'+alt+'" style="width: 100%;height: auto;">')
    );
    return this.config.template(
      item
    )
}
複製代碼

這和函數容許使用用戶傳來的回調函數在渲染以前操做一下模板,用來DIYdom,好比(加邊距,加文字等等)佈局

【核心】實現render渲染函數

Iboot.prototype.render = function(cp, img){
    
    var _this = this
    
    // 獲取一下item模板
    var dom = this.template(cp.src, cp.alt) 
  
    // 獲取加載後的圖片的比例
    var scale = img.width / img.height
    
    // 給item加屬性,保存當前信息,用給Resize的時候讀取,根據信息從新排版
    dom.attr({
      'data-rew': img.width,
      'data-reh': img.height,
      'data-scale': scale
    })
    
    // 計算根據基準高度縮放以後的信息
    var comp = {
      width: scale * this.config.baseHeight,
      height: this.config.baseHeight,
    }
  
    // nowItemWidth的做用就是沒次加元素,就把寬度累加,而後當累加的寬度大於父盒子的寬度的時候,進行總體縮放,縮放完成以後重置爲0
    this.innerData.nowItemWidth += comp.width
    // appendDoms儲存當前列表,縮放以後清空
    this.innerData.appendDoms.push(dom)
    // saveDom是全局的,全部信息都儲存在這,用於以後resize
    this.innerData.saveDom.push(dom)
  
    // 縮放當前dom
    dom.css({
      height: comp.height,
      width: comp.width
    })
    // 添加到父盒子
    this.ele.append(dom)
  
    var compW = this.innerData.nowItemWidth - this.ele.width()
    // 當放不下的時候,進行總體縮放
    if(compW > 0) {
      
      // 超出大小總體縮放
      var nowScale = this.innerData.nowItemWidth / this.getMediaHeight()
      
      var scaleHeight = this.ele.width() / nowScale
      
      // 總體縮放
      $.each(this.innerData.appendDoms, function (i, v) {
        
        var data = $(v).data()
        
        $(v).css({
          height: scaleHeight,
          width:  data.scale * scaleHeight
        })
        
        // 對縮放後的元素進行分組,這個分組很重要,由於當圖片小於排版要求的時候就不會分組,不分組的就隱藏掉。
        $(v).attr('group', _this.innerData.groupid)
        
      })
  
      this.innerData.nowItemWidth = 0
      this.innerData.appendDoms = []
      this.innerData.groupid++
    }
    
  }
複製代碼

總結一下render的思路ui

  • 累計添加子元素,把等比例縮放後的寬度儲存起來
  • 當放不下的時候進行總體縮放
  • 請空儲存的值
  • 以此類推

關於 groupid,由於圖片會出現不符合排版要求的狀況,咱們不對其進行分組,隱藏它們。當resize或者loadmore的時候符合分組要求在顯示它們。

實現resize排版器

resize的思想和render很像,只不過就是考慮了groupid的顯示隱藏。

Iboot.prototype.resize = function(){
    
    var baseHeight = this.getMediaHeight()
    var _this = this
    $.each(this.innerData.saveDom, function (i, v) {
      
      // 首先刪除全部的group id
      $.each(_this.innerData.appendDoms, function (i, v) {
        $(v).removeAttr('groupid')
        $(v).show()
      })
      
      var data = $(v).data()
      
      var cof = {
        height: baseHeight,
        width: baseHeight * data.scale
      }
      _this.innerData.appendDoms.push(v)
      _this.innerData.nowItemWidth += cof.width
  
      var compW = _this.innerData.nowItemWidth - _this.ele.width()
  
      if(compW > 0) {
  
        // 超出大小總體縮放
        var nowScale = _this.innerData.nowItemWidth / _this.getMediaHeight()
  
        var scaleHeight = _this.ele.width() / nowScale
        
        $.each(_this.innerData.appendDoms, function (i, v) {
          var data = $(v).data()
    
          $(v).css({
            height: scaleHeight,
            width: data.scale * scaleHeight
          })
  
          $(v).attr('group', _this.innerData.groupid)
    
        })
  
        _this.innerData.nowItemWidth = 0
        _this.innerData.appendDoms = []
        _this.innerData.groupid++
      }
      
      
    })
  
    _this.innerData.nowItemWidth = 0
    _this.innerData.appendDoms = []
    _this.innerData.groupid = 0
  
    // 隱藏沒有group id 的
    $.each(this.innerData.saveDom, function (k, v) {
      var data = $(v).attr('group')
      if(!data) {
        $(v).hide()
      }
    })
    
  }
複製代碼

loadMore加載更多

Iboot.prototype.loadMore = function(list){
    var _this = this
  
    // 把上次隱藏groupid的加進去
    var coc = []
    $.each(this.innerData.saveDom, function (i, v) {
      var data = $(v).attr('group')
      if(!data) {
        if(!v) {
          return
        }
        var img = $(v).find('img')
        coc.push({
          src: img.attr('src'),
          alt: img.attr('alt'),
        })
        _this.innerData.saveDom.splice(i, 1)
      }
    })
    
    list = coc.concat(list)
    
    this.beforeLoad()
    this.loader(list, function (cp, img) {
      _this.render(cp, img)
    }, function (cp, img, error) {
    
    }, function () {
      _this.afterLoad()
    })
  }
複製代碼

最後把方法拋出到全局

root.Iboot = function(ele, config){
  return new Iboot(ele, config).init();
}
複製代碼

大功告成,前先後後大概用了4個多小時,頭髮要掉光了。。。學無止境,告辭!

相關文章
相關標籤/搜索