JS实现页面瀑布流效果

瀑布流,是比较流行的一种网站页面,视觉表现为参差不齐的多栏布局,随着窗口的缩放会自动计算并重新排序;

 下面是关于瀑布流的示例图:

 实现过程

1.清除默认样式,先创建一个id 为 forcenter 的大盒子;

<div id='forcenter'></div>

2.在index.js 定义一个类,接收大盒子的id 和 需要加载的图片数组;

class waterfall {
    constructor(obj) {
        this.id = obj.id;
        this.imgUrls = obj.imgUrls;
        this.container = document.getElementById(this.id);
        this.container.className = 'forcenter';
    }
}

3.定义一个方法render,加载图片生成dom;

class waterfall {
    constructor(obj) {
        this.id = obj.id;
        this.imgUrls = obj.imgUrls;
        this.container = document.getElementById(this.id);
        this.container.className = 'forcenter';
    }
    render() {
        let flag = 0;   // 用于检测每一张图片都加载完毕
        
        //checkImage 用于防止图片路径不对,加载不出来,导致首屏没有执行resize
        function checkImage(url) {
            return new Promise((resolve, reject) => {
                let img = new Image()
                img.src = url
                img.onload = () => {
                    resolve(img)
                }
                img.onerror = () => {
                    console.log(123);
                    reject()
                }
            })
        }


        this.imgUrls.map((item, i) => {
            checkImage(item).then((img) => {
                console.log("图片正确");
                let div = document.createElement('div');
                div.className = 'item';
                flag++;
                div.appendChild(img);
                this.container.appendChild(div);
            }).catch(() => {
                flag++;
            }).finally(() => {
                //保证所有图片加载完之后再进行排列
                if (flag === this.imgUrls.length) {
                    this.resize();
                }
            })
        });

        let styleE = document.createElement('style');
        //给图片固定200px,保证宽度相同的情况下,高度自适应;
        styleE.innerHTML = `div.item{
        position: absolute;
        transition: all .5s;  /* 使过渡平滑*/
        width : 200px;
        height: auto;
        padding:5px;
        box-sizing: border-box;  /* 非常重要,可将不必要的计算略去 */
      }
      div.item img{
        width: 100%;
        height: auto;
      }
      .forcenter{
        position: relative;
        margin: auto;
      }`;
        this.container.appendChild(styleE);
    }

}

4.定义一个方法 resize ,排序图片

class waterfall {
    constructor(obj) {
        this.id = obj.id;
        this.imgUrls = obj.imgUrls;
        this.container = document.getElementById(this.id);
        this.container.className = 'forcenter';
    }
    
    resize() {
        function getMinH(arr) {
            console.log(arr);
            let flag = {
                left: 0,
                top: 0,
                column: 0
            }

            arr.map((item, i) => {
                if (flag.top === 0) {
                    flag.top = item;
                } else {
                    if (flag.top > item) {  // 找出高度最小的那一列
                        flag.top = item;
                        flag.left = 200 * i;
                        flag.column = i;
                    }
                }
            });

            return flag;
        }

        function setDiv(item, left, top) {
            item.style.left = left + 'px';
            item.style.top = top + 'px';
        }
        let winW = window.innerWidth;
        let itemNum = Math.floor(winW / 200); // 当每一个项的宽度都是固定的时候,需要计算出浏览器一行可以排列几个。
        this.container.style.width = (itemNum * 200) + 'px'; // 用于居中的包裹盒子的宽度

        let saveColumnHeight = [];  // 定义一个数组,用于存储 每一列所有元素的高度 之和
        let items = document.querySelectorAll('.item');
        console.log(items)
        for (let i = 0; i < items.length; i++) {
            if (saveColumnHeight.length < itemNum) {
                saveColumnHeight[i] = items[i].offsetHeight;// 当布局的元素还没占满一行时,继续向数组中添加第一行第i列的高度
                setDiv(items[i], 200 * i, 0);    // 放置div
            } else {  // 当已经占满一行时,就找出每一列的最小高度,然后当前的这个div放在高度最小的那一列
                let pos = getMinH(saveColumnHeight);    //去找高度最小的那一列
                saveColumnHeight[pos.column] += items[i].offsetHeight;
                setDiv(items[i], pos.left, pos.top);    // 放置div
            }
        }
    }
}

5.在页面中实例化 waterfall ,并执行实例中的方法,;

   let W = new waterfall({
            id: 'forcenter',
            imgUrls: [
                "https://gd-hbimg.huaban.com/01d4ff197f1b7c82c5c251e8e8236bb1ab7e0727651a5-WDx8ol_fw658webp",
                "https://gd-hbimg.huaban.com/e320380f3c9178cc0b8310e7c03d8e241ccce13f1bf41d-iPTu0A_fw658webp",
                "https://gd-hbimg.huaban.com/acde98e286be64cb57aa26b0e16668991796d122247433-sFxXXE_fw658webp",
                "https://gd-hbimg.huaban.com/7ebc91824c83e5a6c5a95f432316297e0469b7fbb59fc-6f6dw7_fw658webp",
                "https://gd-hbimg.huaban.com/75e24879bd50b6bdaee6897ecf7df8fed8fc6b321c1ae-IdBFAO_fw658webp",
                "https://gd-hbimg.huaban.com/6c7c6cb1280654293598481ab4caa8ef308f6abc176736-9Dqd8L_fw658webp",
                "https://gd-hbimg.huaban.com/23d645d1dbd6a45d37ad37e4b97d18be91e2dc49de203-lQ7f1c_fw658webp",
                "https://gd-hbimg.huaban.com/144d28eaa9837fc65633e5ab05efcf95a3610c5913f7a5-S26C5f_fw658webp",
                "https://gd-hbimg.huaban.com/f768bc96a779b0daf9dc046551624e76f07285fb13a61b-fPShae_fw658webp",
                "https://gd-hbimg.huaban.com/4e94b094670cb92be05e115e7752e7e7a677721ace7ca-OmpKsJ_fw658webp",
                "https://gd-hbimg.huaban.com/6378e2264b274c2a66c0d7a64243249d3cdd4990230087-YsZfHb_fw658webp",
                "https://gd-hbimg.huaban.com/7879c0d70a9651bfef97dbdbca860d0173fb2083efdfa-JtEY7C_fw658webp",
                "https://gd-hbimg.huaban.com/0ad9ee4917eb9bee29131a6305d91c1b512165f7ae91e-y5vGPb_fw658webp",
                "https://gd-hbimg.huaban.com/18cfb795803a281a3fca234f05a0e8267eab4b08474f4-pvt6dW_fw658webp",
                "https://gd-hbimg.huaban.com/b38ec047337c60dacec8532438e8df1f2f355e4a7739e2-lQkaGs_fw658webp",
                "https://gd-hbimg.huaban.com/1cd188eba7137deba40617e49ff81cf9555cda3730edf-ddVRVj_fw658webp",
                "https://gd-hbimg.huaban.com/d700b15123823599108913ceb94e188563594b2e7c2d4-M2VRbA_fw658webp",
                "https://gd-hbimg.huaban.com/450d20605009f0f5389a31fed68e43d8ba1b93a8617d1-6dGTj0_fw658webp",
                "https://gd-hbimg.huaban.com/e12930b69dc1e0bc3f5a152b7038ac250a9ec35792c97-G9OwPi_fw658webp",
                "https://gd-hbimg.huaban.com/a9900bec233ff1393fa8e23e0e607f20a091c21e429e4-fneOUo_fw658webp",
            ]
        })

        window.onload = () => {
            W.render()
        }
        window.onresize = () => {
            W.resize()
        }

6.结果展示

7.完整代码 

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>瀑布流布局</title>
    <meta name='viewport' content='width=device-width,initial-scale=1.0,user-scalable=no' />
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <div id='forcenter'></div>
    <script src="./index.js"></script>
    <script>
        let W = new waterfall({
            id: 'forcenter',
            imgUrls: [
                "https://gd-hbimg.huaban.com/01d4ff197f1b7c82c5c251e8e8236bb1ab7e0727651a5-WDx8ol_fw658webp",
                "https://gd-hbimg.huaban.com/e320380f3c9178cc0b8310e7c03d8e241ccce13f1bf41d-iPTu0A_fw658webp",
                "https://gd-hbimg.huaban.com/acde98e286be64cb57aa26b0e16668991796d122247433-sFxXXE_fw658webp",
                "https://gd-hbimg.huaban.com/7ebc91824c83e5a6c5a95f432316297e0469b7fbb59fc-6f6dw7_fw658webp",
                "https://gd-hbimg.huaban.com/75e24879bd50b6bdaee6897ecf7df8fed8fc6b321c1ae-IdBFAO_fw658webp",
                "https://gd-hbimg.huaban.com/6c7c6cb1280654293598481ab4caa8ef308f6abc176736-9Dqd8L_fw658webp",
                "https://gd-hbimg.huaban.com/23d645d1dbd6a45d37ad37e4b97d18be91e2dc49de203-lQ7f1c_fw658webp",
                "https://gd-hbimg.huaban.com/144d28eaa9837fc65633e5ab05efcf95a3610c5913f7a5-S26C5f_fw658webp",
                "https://gd-hbimg.huaban.com/f768bc96a779b0daf9dc046551624e76f07285fb13a61b-fPShae_fw658webp",
                "https://gd-hbimg.huaban.com/4e94b094670cb92be05e115e7752e7e7a677721ace7ca-OmpKsJ_fw658webp",
                "https://gd-hbimg.huaban.com/6378e2264b274c2a66c0d7a64243249d3cdd4990230087-YsZfHb_fw658webp",
                "https://gd-hbimg.huaban.com/7879c0d70a9651bfef97dbdbca860d0173fb2083efdfa-JtEY7C_fw658webp",
                "https://gd-hbimg.huaban.com/0ad9ee4917eb9bee29131a6305d91c1b512165f7ae91e-y5vGPb_fw658webp",
                "https://gd-hbimg.huaban.com/18cfb795803a281a3fca234f05a0e8267eab4b08474f4-pvt6dW_fw658webp",
                "https://gd-hbimg.huaban.com/b38ec047337c60dacec8532438e8df1f2f355e4a7739e2-lQkaGs_fw658webp",
                "https://gd-hbimg.huaban.com/1cd188eba7137deba40617e49ff81cf9555cda3730edf-ddVRVj_fw658webp",
                "https://gd-hbimg.huaban.com/d700b15123823599108913ceb94e188563594b2e7c2d4-M2VRbA_fw658webp",
                "https://gd-hbimg.huaban.com/450d20605009f0f5389a31fed68e43d8ba1b93a8617d1-6dGTj0_fw658webp",
                "https://gd-hbimg.huaban.com/e12930b69dc1e0bc3f5a152b7038ac250a9ec35792c97-G9OwPi_fw658webp",
                "https://gd-hbimg.huaban.com/a9900bec233ff1393fa8e23e0e607f20a091c21e429e4-fneOUo_fw658webp",
            ]
        })

        window.onload = () => {
            W.render()
        }
        window.onresize = () => {
            W.resize()
        }

    </script>
</body>

</html>

index.js

class waterfall {
    constructor(obj) {
        this.id = obj.id;
        this.imgUrls = obj.imgUrls;
        this.container = document.getElementById(this.id);
        this.container.className = 'forcenter';
    }
    render() {
        let flag = 0;   // 用于检测每一张图片都加载完毕

        function checkImage(url) {
            return new Promise((resolve, reject) => {
                let img = new Image()
                img.src = url
                img.onload = () => {
                    resolve(img)
                }
                img.onerror = () => {
                    console.log(123);
                    reject()
                }
            })
        }


        this.imgUrls.map((item, i) => {
            checkImage(item).then((img) => {
                console.log("图片正确");
                let div = document.createElement('div');
                div.className = 'item';
                flag++;
                div.appendChild(img);
                this.container.appendChild(div);
            }).catch(() => {
                flag++;
            }).finally(() => {
                if (flag === this.imgUrls.length) {
                    this.resize();
                }
            })
        });

        let styleE = document.createElement('style');

        styleE.innerHTML = `div.item{
        position: absolute;
        transition: all .5s;  /* 使过渡平滑*/
        width : 200px;
        height: auto;
        padding:5px;
        box-sizing: border-box;  /* 非常重要,可将不必要的计算略去 */
      }
      div.item img{
        width: 100%;
        height: auto;
      }
      .forcenter{
        position: relative;
        margin: auto;
      }`;
        this.container.appendChild(styleE);
    }
    resize() {
        function getMinH(arr) {
            console.log(arr);
            let flag = {
                left: 0,
                top: 0,
                column: 0
            }

            arr.map((item, i) => {
                if (flag.top === 0) {
                    flag.top = item;
                } else {
                    if (flag.top > item) {  // 找出高度最小的那一列
                        flag.top = item;
                        flag.left = 200 * i;
                        flag.column = i;
                    }
                }
            });

            return flag;
        }

        function setDiv(item, left, top) {
            item.style.left = left + 'px';
            item.style.top = top + 'px';
        }
        let winW = window.innerWidth;
        let itemNum = Math.floor(winW / 200); // 当每一个项的宽度都是固定的时候,需要计算出浏览器一行可以排列几个。
        this.container.style.width = (itemNum * 200) + 'px'; // 用于居中的包裹盒子的宽度

        let saveColumnHeight = [];  // 定义一个数组,用于存储 每一列所有元素的高度 之和
        let items = document.querySelectorAll('.item');
        console.log(items)
        for (let i = 0; i < items.length; i++) {
            if (saveColumnHeight.length < itemNum) {
                saveColumnHeight[i] = items[i].offsetHeight;// 当布局的元素还没占满一行时,继续向数组中添加第一行第i列的高度
                setDiv(items[i], 200 * i, 0);    // 放置div
            } else {  // 当已经占满一行时,就找出每一列的最小高度,然后当前的这个div放在高度最小的那一列
                let pos = getMinH(saveColumnHeight);    //去找高度最小的那一列
                saveColumnHeight[pos.column] += items[i].offsetHeight;
                setDiv(items[i], pos.left, pos.top);    // 放置div
            }
        }
    }
}

声明:本文所有素材来源:花瓣网 - 陪你做生活的设计师(创意灵感天堂,搜索、发现设计灵感、设计素材) 

猜你喜欢

转载自blog.csdn.net/gsy445566778899/article/details/130881713