动态瀑布流布局的图片墙

要实现动态瀑布流布局的图片墙:要做到两点:
一.实现瀑布流的图片墙,
二.使用函数节流监听window的resize事件
首先:实现瀑布流的图片墙,网上有各种各样式的实现,但是纯css的实现,总是有些bug,不容易控制,所以我使用js进行控制。
它的原理是:首先使用浮动布局,图片可浮动。具体结构:
这里写图片描述
这里写图片描述
这时除了第一行,其他的图片的都有较大的间距。剩下的工作需要js来完成:
①声明变量保存图片墙容器的dom object,声明变量保存图片墙每个图片容器的dom object,声明变量保存第一行图片容器的属性
②计算每行图片的数目,第一行每个图片容器的左边的距离,以及第一行每张图片容器的高度(因为除第一行外都是使用的绝对定位)
③开始计算剩余图片容器的位置,(主要包括图片容器的left和top,每设置一个图片容器的位置,那么就更新第一行图片容器数组的top值,因为判断下张图片容器的位置就是找上一行高度最小的图片容器,在它的下方放置);
**注意:
因为是动态的,所以当窗口变动时,第一行的图片容器数量会改变,所以原来不在第一行之列的元素会进入到第一行,但是此时它们依然是绝对定位,所以要清除绝对定位。
另外一点,如果你的html的font-size使用函数节流,此时瀑布流布局的图片墙也要用,要注意this的指向,我因为使用了面向对象,所以瀑布流布局的图片墙使用节流时要指向我的对象。**
**
完整代码:

<template>
    <ul class="photos-wall clear" ref="photosWall">
        <li class="photo" ref="photo" v-for="img in images" :key="img.index"><img :src="img.src" alt="瀑布流图片" /></li>
    </ul>
</template>

<script type="text/javascript">
    import Base from '../assets/js/base.js'

    export default {
        data() {
            return {
                images: [],
                waterfullBoxObj: null,
                waterfullElemObjs: null
            }
        },
        created() {
            this.init();
        },
        mounted() {
            this.initGetDomObj();
        },
        methods: {
            init: function () {  // 一切数据和函数的入口
                this.initBaseDatas();
            },
            initBaseDatas: function () {  //初始化data中的所有数据
                this.initImagesData()
            },
            initImagesData: function () {  //初始化data中images属性的初始值
                let images = [
                    {'index': 1, 'src': '../../static/imgs/waterfull/hy1.jpeg'},
                    {'index': 2, 'src': '../../static/imgs/waterfull/hy2.jpg'},
                    {'index': 3, 'src': '../../static/imgs/waterfull/hy3.jpg'},
                    {'index': 4, 'src': '../../static/imgs/waterfull/hy4.jpg'},
                    {'index': 5, 'src': '../../static/imgs/waterfull/hy5.jpg'},
                    {'index': 6, 'src': '../../static/imgs/waterfull/hy6.jpg'},
                    {'index': 7, 'src': '../../static/imgs/waterfull/hy7.jpg'},
                    {'index': 8, 'src': '../../static/imgs/waterfull/hy8.jpg'},
                    {'index': 9, 'src': '../../static/imgs/waterfull/hy9.jpg'},
                    {'index': 10, 'src': '../../static/imgs/waterfull/hy10.jpg'}
                ];
                this.images = images;
            },
            initGetDomObj: function () {  //初始化获取的dom元素的对象
                let self = this;
                // 延迟获取dom元素,因为图片未加载完毕,获取的元素的高度不正确
                let timer = setTimeout(function () {
                    self.waterfullBoxObj = self.$refs.photosWall;  //获取瀑布流容器对象
                    self.waterfullElemObjs = self.$refs.photo; //获取瀑布流容器中元素对象
                    let waterfullPhotos = ProxySingletonWaterfullPhotos(self.waterfullBoxObj, self.waterfullElemObjs);
                    window.addEventListener('resize', Base.throttle(waterfullPhotos.init, 200, waterfullPhotos), false);
                }, 200);
            }
        }
    }

    let isDOM = (typeof HTMLElement === 'object')?
                function(obj){
                    return obj instanceof HTMLElement;
                }:
                function(obj){
                    return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
                };

    /**
     * 使用代理模式创建WaterfullPhotos类的单例模式
     */
    var ProxySingletonWaterfullPhotos = (function () {
        let instanse;
        return function (box, items) {
            if (!instanse) {
                instanse = new WaterfullPhotos(box, items);
            }
            return instanse;
        }
    }());

    /**
     * 瀑布流布局的图片墙
     * @param object box   [description]
     * @param items items [description]
     */
    function WaterfullPhotos (box, items) {
        // 检测参数
        if (!box || !items) {
            throw new Error('function WaterfullPhotos arguments can not missing!');
            return ;
        }
        if (!isDOM(box)) {
            throw new Error('function WaterfullPhotos first param must be a dom object!');
            return ;
        }
        if (!Array.isArray(items) || (items.length <= 0)) {
            throw new Error('function WaterfullPhotos second param must be a dom object array!');
            return ;
        }
        for (let i = 0, len = items.length; i < len; i++) {
            if (!isDOM(items[i])) {
                throw new Error('function WaterfullPhotos second param must be a dom object array!');
                return ;
            }
        }

        this.box = box;             //图片墙的容器
        this.items = items;         //图片墙的容器中的每张图片的盒子容器
        this.firstColum = [];       //图片墙的容器的第一行图片组
        this.columnNum = 0;         //图片墙的容器每行图片的数目

        // 启动函数
        this.init();
    }

    /**
     * 获取瀑布流图片第一列的属性
     * @return {[type]} [description]
     */
    WaterfullPhotos.prototype.getWaterfullFirstColumn = function () {  
        // 计算每一列的数目(总宽度/每个元素的宽度[元素的宽度相等])
        this.columnNum = Math.floor(this.box.offsetWidth / this.items[0].offsetWidth);
        let waterfullElemObj_w = this.items[0].offsetWidth;

        this.clearFirstColumnPhotosPosition();

        let obj = {},           // 存放第一列元素的属性
            _firstColum = [];   //保存第一列元素    
        for (let i = 0; i < this.columnNum; i++) {
            obj.width = waterfullElemObj_w;
            obj.left = i * waterfullElemObj_w;
            obj.top = this.items[i].offsetHeight;
            _firstColum.push(obj);
            obj = {};
        }

        this.firstColum = _firstColum;

        obj = null;
        _firstColum = null;
    }

    /**
     * 清除第一行图片组中某些元素的绝对定位
     * @return {[type]} [description]
     */
    WaterfullPhotos.prototype.clearFirstColumnPhotosPosition = function () { 
        // 当窗口触发resize事件时,可能原来设置绝对为的元素加入到第一行,所以要清除绝对定位
        for (let i = 0; i < this.columnNum; i++) {
            if (this.items[i].style.position === 'absolute') {
                this.items[i].style.position = '';
                this.items[i].style.top = '';
                this.items[i].style.left = '';
            }
        }
    }

    /**
     * 设置图片墙除第一行图片其他图片的位置
     * @param array arr 除第一行图片盒子的其他图片盒子组成数组
     */
    WaterfullPhotos.prototype.setWaterfullOtherPhotoPosition = function (arr) {
        for(let i = 0, item; item = arr[i++];) {
            let minObj = this.getObjArrayAttributeMinValue(this.firstColum, 'top');
            item.style.position = 'absolute';
            item.style.top = this.firstColum[minObj.minIndex].top + 'px';
            this.firstColum[minObj.minIndex].top += item.offsetHeight;  //更新当列据顶部的高度
            item.style.left = this.firstColum[minObj.minIndex].left + 'px';
        }
    }
    /**
     * 获取对象数组某个属性的最小值
     * @param  array arr  需要获取最小值和最小值位置的目标对象
     * @param  array attr 需要获取最小值和最小值位置的目标对象的属性
     * @return object     获取的最小值和最小值位置
     */
    WaterfullPhotos.prototype.getObjArrayAttributeMinValue = function (arr, attr) {
        let _arr = [];
        for (let i = 0, item; item = arr[i++];) {
            if (item.hasOwnProperty(attr)) {
                _arr.push(item[attr]);
            }
        }
        let minValue = Math.min.apply(null, _arr),
            minIndex = _arr.indexOf(minValue);
        return {
            minValue: minValue,
            minIndex: minIndex
        };
    }

    /**
     * WaterfullPhotos类的启动函数
     * @return {[type]} [description]
     */
    WaterfullPhotos.prototype.init = function () {
        this.getWaterfullFirstColumn();
        this.setWaterfullOtherPhotoPosition(this.items.slice(this.firstColum.length));
    }
</script>

<style lang="scss" scoped>
    /*photos wall style*/
    .photos-wall{
        position: relative;
        width: 100%;
        min-height: 100%;
        font-size: inherit;
        .photo{
            display: inline-block;
            width: 15.625em;
            min-width: 5.5em;
            float: left;
            font-size: inherit;
            img{
                width: 100%;
                vertical-align: middle;
            }
        }
    }
</style>

base.js

function isPC () {
    // 判断用户的设备类型是否是PC端
    let userAgentInfo = navigator.userAgent;
    const AGENTS = ["Android", "iPhone",
             "SymbianOS", "Windows Phone",
             "iPad", "iPod"];
    let flag = true;
    for (var v = 0; v < AGENTS.length; v++) {
        if (userAgentInfo.indexOf(AGENTS[v]) > 0) {
            flag = false;
            break;
        }
    }
    return flag;
}

/*
    用于屏幕的适配
 */
function adaptive () {
    let htmlObj = document.querySelector('html') || document.getElementsByTagName('html')[0] || document.body;
    const PC_BASE_SEIZE = 136.6,
        MOBILE_BASE_SEIZE = 37.5;
    try{
        if (!htmlObj) {
            throw new Error('Get the html element error!');
        }
        let client_w = htmlObj.clientWidth,
            baseFontSize = client_w/PC_BASE_SEIZE;
        if (!isPC()) {
            baseFontSize = client_w/MOBILE_BASE_SEIZE;
        }
        htmlObj.style.fontSize = baseFontSize + 'px';
    } catch (e) {
        console.log('base.js/function '+ this.getName +' error:', e);
    }
}

// 函数节流
let throttle =  function (fn, interval, context) {
    let _self = fn,             //保存待执行函数的引用
        firstTime = true,       //是否是第一次调用
        timer = null;           //定时器
    return function () {
        let args = arguments,   //保存参数
            _me = context || this;          //保存throttle函数的引用

        //第一次执行不需要延迟执行
        if (firstTime) {
            _self.apply(_me, args);
            return firstTime = false;
        }

        //如果timer存在说明函数上一次延期汗没有执行完毕
        if (timer) {
            return false;
        }

        timer = setTimeout(function () {
            clearTimeout(timer);
            timer = null;
            _self.apply(_me, args);
        }, interval || 400);
    };
}

// 窗口尺寸改变触发的事件
function resize () {
    window.addEventListener('resize', throttle(adaptive, 300), false);
}

module.exports = {
    resize: resize,
    isPC: isPC,
    throttle: throttle,
    init: function () {
        adaptive();
    }
};
/*# sourceMappingURL=base.js.map */

猜你喜欢

转载自blog.csdn.net/babulongbo/article/details/79630881
今日推荐