瀑布流 + 共享效果

文章展示了如何使用JavaScript和CSS3实现瀑布流布局,通过计算容器宽度动态创建列数,并在用户点击元素时实现共享效果,即复制元素并居中显示,同时提供了相应的HTML结构和CSS样式作为支持。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

瀑布流 + 共享效果

- 实现原理 : 展示的元素固定宽度,通过计算容器的宽度判断该内容应该创建多少列
- 应创建的列数 = 包含数组的长度
- 每次添加一个元素都往这个数组最小的一项添加上元素的高度
- 计算时通过获取数组最小一项的下标,计算出left 和 top 值 + gap值就是总体效果实现
- 每次更新窗口变化重新计算

在这里插入图片描述

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body,
        html {
            margin: 0;
            padding: 0;
        }

        .container {
            width: 90%;
            margin: 0 auto;
            padding: 10px;
            box-sizing: border-box;
            position: relative;
        }

        .container div {
            transition: .5s;
        }

        .container div {
            position: absolute;
            /* css3属性,表示过渡效果, 图片的样式变化在0.3秒内完成,而不是瞬间完成 */
            transition: 0.3s;
            width: 220px;
        }
        #mask{
            display: none;
            position: fixed;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: #ccc;
            z-index: 1;
            opacity: .6;
            
        }
    </style>
</head>

<body>
    <div id="mask"></div>
    <div class="container"></div>
</body>

</html>
<script>
    const divContainer = document.querySelector('.container');
    const mask = document.querySelector('#mask')

    // 计算 margin 固定宽度
    const marginGap = 20
    let oWidth = 220;
    const oHeight = { max: 600, min: 250 }
    const ShowItem = 20
    const Gap = 1
    var timerId = null;
    var clonedElement = null;

    // 计算当前盒子宽度 / 盒子宽度 + 边距
    function createDom(n) {
        for (var i = 0; i < n; i++) {
            let nDom = document.createElement('div');
            nDom.style.width = oWidth + 'px'
            nDom.style.height = getRandomNumber() + 'px'
            nDom.style.backgroundColor = getRandomColor()
            nDom.classList.add('item')
            divContainer.appendChild(nDom)
        }
        SetPosition()

    }
    createDom(ShowItem)



    function SetPosition() {
        function cal() {
            // 获取容器 宽度
            var containerWidth = divContainer.getBoundingClientRect().width
            // 计算列的数量
            var columns = Math.floor(containerWidth / oWidth);

            // 间隙数量
            var spaceNumber = columns + 1;
            var leftSpace = containerWidth - columns * oWidth; //计算剩余的空间
            var space = leftSpace / spaceNumber; //每个间隙的空间
            return {
                space: space,
                columns: columns,
            };
        }
        var info = cal(); //得到列数,和 间隙的空间
        var nextTops = new Array(info.columns); //该数组的长度为列数,每一项表示该列的下一个图片的纵坐标
        nextTops.fill(0); //将数组的每一项填充为0
        for (var i = 0; i < divContainer.children.length; i++) {
            var cDom = divContainer.children[i];
            var minTop = Math.min.apply(null, nextTops);
            cDom.style.top = minTop + 'px';
            //重新设置数组这一项的下一个top值
            var index = nextTops.indexOf(minTop); //得到使用的是第几列的top值
            nextTops[index] += cDom.getBoundingClientRect().height + info.space;
            //横坐标
            var left = (index + 1) * info.space + index * oWidth;
            cDom.style.left = left + 'px';
        }
        var max = Math.max.apply(null, nextTops); //求最大值
        divContainer.style.height = max + 'px'; //3. 设置容器的高度
    }


    window.addEventListener('resize', resizeHandler, false)


    function resizeHandler() {
        if (timerId) {
            clearTimeout(timerId)
        }
        timerId = setTimeout(SetPosition, 300)

    }

    // 配合共享效果
    divContainer.addEventListener('click',handlerClick,false)

    function handlerClick(e){
        if(e.target.classList.contains('item')){
            let curDom = e.target;
            if(clonedElement) return
            clonedElement = curDom.cloneNode(true); 
            clonedElement.style.zIndex = 3;
            clonedElement.classList.add('copyEle')
            divContainer.appendChild(clonedElement)

            const {left, top, width,height} = clonedElement.getBoundingClientRect()
            let saveOption = {
                left,
                top,
                width,
                height
            }
            clonedElement.style.left = '50%'
            clonedElement.style.top = (document.documentElement.scrollTop + saveOption.height / 2 + 30) + 'px'
            clonedElement.style.zIndex = 2
            clonedElement.style.transform = 'translate(-50%, -50%)';
            toggleMask()
        }
   
    }

    function toggleMask(){
        const computedStyle = window.getComputedStyle(mask);
        let display = computedStyle.getPropertyValue('display')
        display == 'none'? mask.style.display = 'block' : mask.style.display = 'none';
    }

    function toggleClonedElementClose(){
        if(clonedElement){
            divContainer.removeChild(clonedElement)
            clonedElement = null
        }
    }

    mask.addEventListener('click',function(){
        toggleMask()
        toggleClonedElementClose()
    })



    // ----------------------------------------



    function getRandomNumber(props = oHeight) {
        // 生成 0 到 1 之间的随机数
        const random = Math.random();
        const { max, min } = props
        // 将随机数转换为指定范围内的数值
        const range = max - min;
        const randomNumber = Math.floor(random * range) + min;
        return randomNumber;
    }

    function getRandomColor() {
        // 生成红、绿、蓝三个通道的随机值
        const red = Math.floor(Math.random() * 256);
        const green = Math.floor(Math.random() * 256);
        const blue = Math.floor(Math.random() * 256);

        // 将通道值拼接成 CSS 颜色字符串
        const color = `rgb(${red}, ${green}, ${blue})`;

        return color;
    }

</script>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值