js多个元素随机且不重叠分布在页面中

最近,公司要做一个类似挖矿的项目,大概其是当用户登录进入首页后,如果用户有已经生成的原力值,则在其点击原力值后可以类似蚂蚁森林那样收集原力值,当用户将所有的原力值收集完毕后开始提醒用户新的原力值正在生成中,待新的原力值生成后,用户可以继续以上的操作收集原力值。如下图:

以上是一种逻辑,还有一种是当用户前一天有剩余的原力值没有收集时,在第二天收集完当天的已生成的原力值后,前一天的原力值还可以出现在页面当中继续供用户收集(具体的情况,看你公司的实际业务需求,比如可以设置三天内的原力值都能收集,也可以设置两天内的原力值可供收集等)。

本文不考虑后端业务逻辑的实现,只分享前端多个原力值在页面中的随机不重叠分布的实现方法,在此之前,我本来想参考网易星球的实现方法(算法),但人家的是APP的项目,根本看不到具体是如何实现的,后来又参考了其他的实现方法,发现其虽然也是有一定的随机性,但元素距离左边的距离其实是固定死的,只有距离顶部的距离是随机的,而且元素基本上就是只分两行随机分布。如下图:

圆圈1那个圆其实永远都在第一行的第一个位置,其唯一变化的就是它距离顶部的距离,其他的圆圈也是类似,这样给人的效果就不理想。再后来,也参考过其他的一些写法,效果都不好。那么,以下就是本篇博客所要实现的代码,妥妥滴的满足了开发的需要:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no,viewport-fit=cover">
<title>js多个元素随机且不重叠分布在页面中</title>
<script>
//计算根节点HTML的字体大小
function resizeRoot(width) {
    var deviceWidth = document.documentElement.clientWidth,
        num = width,
        num1 = num / 100;
    if (deviceWidth > num) {
        deviceWidth = num;
    }
    document.documentElement.style.fontSize = deviceWidth / num1 + "px";
}
//根节点HTML的字体大小初始化
resizeRoot(750);

window.onresize = function () {
    resizeRoot(750);
};
</script>
<style>
*{margin:0;padding:0;}
.demo{height:5rem;position:relative;}
img{.8rem;height:.8rem;position:absolute;border-radius:50%;}
</style>
</head>
<body>
    <div class="demo"></div>
    <script>
        createBubble(10);   //初始化气泡
        function createBubble(num){
            var iconWidth = 60;   //值越大,元素左右间隔越大
            var iconHeight = 60;  //值越大,元素上下间隔越大
            var targetHeight = document.querySelector(".demo").offsetHeight;
            var targetWidth = document.querySelector(".demo").offsetWidth;            
            var _tmpArray = [];
            var html = '';
            //当放置的元素的宽高大于浏览器窗口的宽高时,直接返回
            if(targetWidth < iconWidth || targetHeight < iconHeight){
                return false;   
            }
            
            var xNum = parseInt(targetWidth / iconWidth, 10);    //用浏览器的宽度除以一个元素的宽度可算出浏览器窗口内一行可以放置元素的个数
            var yNum = parseInt(targetHeight / iconHeight, 10);  //用浏览器的高度除以一个元素的高度可算出浏览器窗口内一列可以放置元素的个数
            var allNum = xNum * yNum;   //浏览器窗口内总共可以放置元素的个数
            //当需要放置的元素的个数超过浏览器窗口内总共可以放置的元素的个数时,则返回
            if(num >= allNum){
                return false;
            }        

            for(var i = 0; i < allNum; i++){
                _tmpArray.push(i);
            }

            var xStart = 0, yStart = 0;

            while(num){
                var pointer = Math.floor(Math.random() * allNum);    //向下取整取出0到allnum之间的任意一个整数
                //如果数组_tmpArray中不存在第pointer值,则继续
                if(!_tmpArray[pointer]){
                    continue;
                }
                
                delete _tmpArray[pointer];   //删除数组_tmpArray中第pointer个值
                yStart = parseInt(pointer / xNum, 10) * iconWidth;
                xStart = (pointer % xNum) * iconHeight;

                html += "<img src='http://tp1.sinaimg.cn/1642634100/50/5613120647/0' style='top:" + yStart + "px;left:" + xStart + "px'/>";
                num--;
            }
            document.querySelector(".demo").innerHTML = html;
        }
    </script>
</body>
</html>

本文代码参考自:https://segmentfault.com/q/1010000000188540

原文地址:https://www.cnblogs.com/tnnyang/p/9089051.html