【实战】AJAX之『瀑布流』

一、瀑布流的实现

(1)书写思路

  1. 保存图片高度到数组:先把第一行图片的高度求出并放在一个数组
  2. 找到最小值及索引号:根据Math.min找到数组中的最小数,再根据indexOf找到出相对应的索引号
  3. 设置第六张图左边距:根据索引找到数组中的图片,把它的offsetLeft值赋给第六张图片
  4. 设置第六张图上边距:再根据索引找到数组中保存的高度+10,赋给第六张图片的offsetTop
  5. 改变当前索引的高度:把当前索引高度更改为数组最低高度+第六张图片的高度+10

第一行图片确定好了以后下面的图片就不用像第一行这么排了,因为下面的图片是一张一张的排的,它的left值和top值和第一行的不一样了,它的left值是数组最短的那一列,top值是数组最短高度加上10


每次图片处理完了以后,都要改变的当前idx值的高度

(2)源码

; (function (doc) {

    var oItems = doc.getElementsByClassName('wf-item'),
        oItemsLen = oItems.length,
        _arr = [];

    var init = function () {
        setImgPos()
    }

    function setImgPos() {
        var item;

        for (var i = 0; i < oItemsLen; i++) {
            item = oItems[i];
            item.style.width = '232px';

            // 给第一行图片的top值设置为零,并把高度放入数组
            if (i < 5) {
                _arr.push(item.offsetHeight);
                item.style.top = '0';
                
                if ((i + 1) % 5 === 1) { // 找出每行的第一张图片,并把left值设置为0
                    item.style.left = '0';
                } else {
                    item.style.left = i * (232 + 10) + 'px';
                }
            } else {
                minIdx = getMinIdx(_arr);
                item.style.left = oItems[minIdx].offsetLeft + 'px';
                item.style.top = (_arr[minIdx] + 10) + 'px';
                _arr[minIdx] += (item.offsetHeight + 10);
            }
        }
    }

    function getMinIdx(arr) {
        // 找数组里面最小数的索引号
        return [].indexOf.call(arr, Math.min.apply(this, arr));

    }

    // 避免图片加载时的空白
    window.onload = function () {
        init();
    }

})(document);

二、插件封装

(1)写前分析

配置项

  1. 外层盒子 oWrapper
  2. 列数 column
  3. 间隙 gap

(2)源码

普通版

; (function (doc) {

    var Waterfall = function (wrapper, opt) {
        this.oWrapper = doc.getElementsByClassName(wrapper)[0];
        this.column = opt.column;
        this.gap = opt.gap;
        this.imgAPI = opt.imgAPI;
        this.itemWidth = (this.oWrapper.offsetWidth - (this.column - 1) * this.gap) / this.column;
        this.pageNum = 0;
        this.pageSize = 0;
        this.heightArr = [];
    }

    Waterfall.prototype = {
        init: function () {
            this.getImgDatas(this.pageNum);
            this.bindEvent();
        },

        bindEvent: function () {
            window.addEventListener('scroll', this.scrollToBottom.bind(this), false);
        },

        scrollToBottom: function () {
            if (getScrollTop() + getWindowHeight() == getScrollHeight()) {
                this.pageNum++;

                if (this.pageNum <= this.pageSize - 1) {
                    this.getImgDatas(this.pageNum);
                }
            }
        },

        getImgDatas: function (pageNum) {
            var _self = this;

            xhr.ajax({
                url: this.imgAPI,
                type: 'POST',
                dataType: 'JSON',
                data: {
                    pageNum: pageNum,
                },
                success: function (data) {
                    if (data != 'NO DATA') {
                        var pageData = JSON.parse(data.pageData);
                        _self.pageSize = parseInt(data.pageSize);
                        _self.renderList(pageData, _self.pageNum);
                    }
                }
            })
        },

        renderList: function (data, pageNum) {
            var _self = this,
                oItems = null,
                minIdx = -1; //数组索引保存默认值一定是-1

            data.forEach(function (elem, idx) {
                var oItem = doc.createElement('div'),
                    oImg = new Image(),
                    oTitle = doc.createElement('div'),
                    itemLeft = (idx + 1) % _self.column === 1 ? '0' : idx * (_self.itemWidth + _self.gap);

                oItem.className = 'wf-item';
                oItem.style.width = _self.itemWidth + 'px';
                oItem.style.height = (elem.height * _self.itemWidth / elem.width + 44) + 'px';
                oImg.src = elem.img;
                oTitle.innerHTML = '<p>测试文本</p>';
                oTitle.className = 'title-box';

                oItem.appendChild(oImg);
                oItem.appendChild(oTitle);
                _self.oWrapper.appendChild(oItem);

                oItems = doc.getElementsByClassName('wf-item');
                if (idx < _self.column && pageNum == 0) {
                    _self.heightArr.push(oItem.offsetHeight);
                    oItem.style.top = '0';
                    oItem.style.left = itemLeft + 'px';
                } else {
                    minIdx = getMinIdx(_self.heightArr);
                    oItem.style.left = oItems[minIdx].offsetLeft + 'px';
                    oItem.style.top = (_self.heightArr[minIdx] + _self.gap) + 'px';
                    _self.heightArr[minIdx] += (oItems[idx].offsetHeight + _self.gap);
                }
                oImg.style.opacity = '1';
            });
        }
    }

    function getMinIdx(arr) {
        return [].indexOf.call(arr, Math.min.apply(null, arr));
    }

    // 抛到全局
    window.Waterfall = Waterfall;

})(document);

优化版

; (function (doc) {
    var Waterfall = function (wrapper, opt) {
        this.oWrapper = doc.getElementsByClassName(wrapper)[0];
        this.column = opt.column;
        this.gap = opt.gap;
        this.imgAPI = opt.imgAPI;
        this.itemWidth = (this.oWrapper.offsetWidth - (this.column - 1) * this.gap) / this.column;
        this.pageNum = 0;
        this.pageSize = 0;
        this.heightArr = [];
    }

    Waterfall.prototype.init = function () {
        this.getImgDatas(this.pageNum);
        this.bindEvent();
    }

    Waterfall.prototype.bindEvent = function () {
        window.addEventListener('scroll', this.scrollToBottom.bind(this), false);
    }

    Waterfall.prototype.scrollToBottom = function () {
        if (getScrollTop() + getWindowHeight() == getScrollHeight()) {
            this.pageNum++;

            if (this.pageNum <= this.pageSize - 1) {
                this.getImgDatas(this.pageNum);
            }
        }
    }

    Waterfall.prototype.getImgDatas = function (pageNum) {
        var _self = this;

        xhr.ajax({
            url: this.imgAPI,
            type: 'POST',
            dataType: 'JSON',
            data: {
                pageNum: pageNum,
            },
            success: function (data) {
                if (data != 'NO DATA') {
                    var pageData = JSON.parse(data.pageData);
                    _self.pageSize = parseInt(data.pageSize);
                    _self.renderList(pageData, _self.pageNum);
                }
            }
        })
    }

    Waterfall.prototype.renderList = function (data, pageNum) {
        var oFrag = doc.createDocumentFragment();

        data.forEach(function (elem, idx) {
            var minIdx = getMinIdx(this.heightArr);

            var oItem = doc.createElement('div'),
                oImg = new Image();

            var itemLeft = (idx + 1) % this.column === 1 ? '0' : idx * (this.itemWidth + this.gap),
                minHeightElemLeft = minIdx === 0 ? 0 : (minIdx * (this.itemWidth + this.gap)),
                itemHeight = elem.height * this.itemWidth / elem.width;

            oItem.className = 'wf-item';
            oItem.style.width = this.itemWidth + 'px';
            oItem.style.height = (elem.height * this.itemWidth / elem.width) + 'px';
            oImg.src = elem.img;

            oItem.appendChild(oImg);
            oFrag.appendChild(oItem);

            if (idx < this.column && pageNum == 0) {
                this.heightArr.push(itemHeight);
                oItem.style.top = '0';
                oItem.style.left = itemLeft + 'px';
            } else {
                oItem.style.left = minHeightElemLeft + 'px';
                oItem.style.top = (this.heightArr[minIdx] + this.gap) + 'px';
                this.heightArr[minIdx] += (itemHeight + this.gap);
            }
            oImg.style.opacity = '1';
        }, this);

        this.oWrapper.appendChild(oFrag);
    }

    function getMinIdx(arr) {
        return [].indexOf.call(arr, Math.min.apply(null, arr));
    }

    // 抛到全局
    window.Waterfall = Waterfall;

})(document);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值