JS实现在某一区域中多个元素随机显示且不重叠


前言

如何实现在某一区域中多个元素随机显示且不重叠?
在这里插入图片描述


一、实现方案

  • 随机数
    根据生成的随机数设置div容器的top、left值;
  • 碰撞检测
    检测两个元素直接是否存在重叠;

二、主要代码

  • 设置div的 topleft
 		/***
         * @name computed
         * @description 计算每个盒子的left top
         * @params divArr 随机布局的div数组
         */
        function computed(divArr) {
          maxDimensions = getMaxDimension(divArr);
          var widthBoundary = maxDimensions.maxWidth;
          var heightBoundary = maxDimensions.maxHeight;

          for (var i = 0; i < divArr.length; i++) {
            rDivLeft = getRDivNumber(
              widthBoundary,
              window.innerWidth - widthBoundary
            );
            rDivTop = getRDivNumber(
              heightBoundary,
              window.innerHeight - heightBoundary
            );
            divArr[i].style.left = rDivLeft + "px";
            divArr[i].style.top = rDivTop + "px";
          }
          examineEach();
        }
        computed(allDiv);
  • 碰撞检测
		/***
         * @name isCollision
         * @description a,b为两个任意盒子,检测其是否碰撞
         * @params a
         * @params b
         * @return Boolean
         */
        function isCollision(a, b) {
          var a_l = a.offsetLeft; // a_l为a盒子左侧偏移量
          var a_t = a.offsetTop; // a_t为a盒子顶部偏移量
          var a_r = a_l + a.offsetWidth; // a_r为a盒子右侧距页面左侧的距离
          var a_b = a_t + a.offsetHeight; // a_b为a盒子底部距页面最顶端的距离
          var b_l = b.offsetLeft; // b_l等为b盒子 同上解释
          var b_t = b.offsetTop; // b_t为b盒子顶部偏移量
          var b_r = b_l + b.offsetWidth; // b_r为b盒子右侧距页面左侧的距离
          var b_b = b_t + b.offsetHeight; // b_b为b盒子底部距页面最顶端的距离

          if (b_r < a_l || b_b < a_t || a_r < b_l || a_b < b_t) {
            // 当满足此条件时,没有发生碰撞,此时返回值为false没有检测到碰撞
            return false;
          } else {
            // 否则为true,即发生碰撞
            return true;
          }
        }
		/***
         * @name examineEach
         * @description 检查每一个盒子之间是否重叠
         */
        function examineEach() {
          maxFrequency += 1;
          for (var i = 0; i < allDiv.length; i++) {
            for (var j = i + 1; j < allDiv.length; j++) {
              if (isCollision(allDiv[i], allDiv[j]) && maxFrequency < 9000) { // maxFrequency 避免无限循环
                // 如果重叠 再次计算位置
                computed([allDiv[i], allDiv[j]]);
              }
            }
          }
        }

三、完整代码

<!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>多个元素随机定位显示且不重叠</title>
  </head>
  <style>
    .rDiv {
      width: 60px;
      height: 60px;
      position: absolute;
      text-align: center;
      color: #fff;
      font-size: 20px;
    }

    .rDiv1 {
      background-color: pink;
      width: 100px;
      height: 150px;
    }

    .rDiv2 {
      background-color: skyblue;
      width: 80px;
      height: 140px;
    }

    .rDiv3 {
      background-color: goldenrod;
      width: 70px;
      height: 120px;
    }

    .rDiv4 {
      background-color: sandybrown;
      width: 120px;
      height: 180px;
    }

    .rDiv5 {
      background-color: silver;
      width: 160px;
      height: 200px;
    }
    .rDiv6 {
      background-color: slategray;
      width: 200px;
      height: 280px;
    }
    .rDiv7 {
      background-color: blanchedalmond;
      width: 300px;
      height: 200px;
    }
    .rDiv8 {
      background-color: cyan;
      width: 260px;
      height: 180px;
    }
  </style>
  <body>
    <div class="rDiv rDiv1">Div1</div>
    <div class="rDiv rDiv2">Div2</div>
    <div class="rDiv rDiv3">Div3</div>
    <div class="rDiv rDiv4">Div4</div>
    <div class="rDiv rDiv5">Div5</div>
    <div class="rDiv rDiv6">Div6</div>
    <div class="rDiv rDiv7">Div7</div>
    <div class="rDiv rDiv8">Div8</div>
    <button onclick="javascript:window.changePosition()">点击随机位置</button>
  </body>
  <script>
    var allDiv = document.getElementsByClassName("rDiv");
    var maxFrequency = 0; // 计算的最大次数

    function changePosition() {
      /***
       * @name getMaxDimension
       * @description 返回div的最大宽度和最大高度
       * @params divArr div数组
       * @return Object
       */
      function getMaxDimension(divArr) {
        var maxWidth = 0;
        for (var i = 0; i < divArr.length; i++) {
          if (divArr[i].offsetWidth > maxWidth) {
            maxWidth = divArr[i].offsetWidth;
          }
        }
        var maxHeight = 0;
        for (var i = 0; i < divArr.length; i++) {
          if (divArr[i].offsetHeight > maxHeight) {
            maxHeight = divArr[i].offsetHeight;
          }
        }
        var values = { maxWidth: maxWidth, maxHeight: maxHeight };
        return values;
      }

      /***
       * @name getRDivNumber
       * @description 返回一个任意的随机数
       * @params min
       * @params max
       * @return Number
       */
      function getRDivNumber(min, max) {
        return Math.random() * (max - min) + min;
      }

      /***
       * @name isCollision
       * @description a,b为两个任意盒子,检测其是否碰撞
       * @params a
       * @params b
       * @return Boolean
       */
      function isCollision(a, b) {
        var a_l = a.offsetLeft; // a_l为a盒子左侧偏移量
        var a_t = a.offsetTop; // a_t为a盒子顶部偏移量
        var a_r = a_l + a.offsetWidth; // a_r为a盒子右侧距页面左侧的距离
        var a_b = a_t + a.offsetHeight; // a_b为a盒子底部距页面最顶端的距离
        var b_l = b.offsetLeft; // b_l等为b盒子 同上解释
        var b_t = b.offsetTop; // b_t为b盒子顶部偏移量
        var b_r = b_l + b.offsetWidth; // b_r为b盒子右侧距页面左侧的距离
        var b_b = b_t + b.offsetHeight; // b_b为b盒子底部距页面最顶端的距离

        if (b_r < a_l || b_b < a_t || a_r < b_l || a_b < b_t) {
          // 当满足此条件时,没有发生碰撞,此时返回值为false没有检测到碰撞
          return false;
        } else {
          // 否则为true,即发生碰撞
          return true;
        }
      }

      /***
       * @name computed
       * @description 计算每个盒子的left top
       * @params divArr 随机布局的div数组
       */
      function computed(divArr) {
        var	maxDimensions = getMaxDimension(divArr);
        var widthBoundary = maxDimensions.maxWidth;
        var heightBoundary = maxDimensions.maxHeight;

        for (var i = 0; i < divArr.length; i++) {
          let rDivLeft = getRDivNumber(
            widthBoundary,
            window.innerWidth - widthBoundary
          );
          let rDivTop = getRDivNumber(
            heightBoundary,
            window.innerHeight - heightBoundary
          );
          divArr[i].style.left = rDivLeft + "px";
          divArr[i].style.top = rDivTop + "px";
        }
        examineEach();
      }
      computed(allDiv);

      /***
       * @name examineEach
       * @description 检查每一个盒子之间是否重叠
       */
      function examineEach() {
        maxFrequency += 1;
        for (var i = 0; i < allDiv.length; i++) {
          for (var j = i + 1; j < allDiv.length; j++) {
            if (isCollision(allDiv[i], allDiv[j]) && maxFrequency < 9000) {
              // maxFrequency 避免无限循环
              // 如果重叠 再次计算位置
              computed([allDiv[i], allDiv[j]]);
            }
          }
        }
      }
    }
    changePosition();
  </script>
</html>

四、最终效果

在这里插入图片描述

五、总结

  • 父级盒子
    当前是以浏览器的窗口宽高作为父级盒子的尺寸,若是想自定义父级盒子尺寸
    可将 computed 函数中的 window.innerWidthwindow.innerHeight 修改成对应的和盒子的宽高
    例如:
		for (var i = 0; i < divArr.length; i++) {
          let rDivLeft = getRDivNumber(
            widthBoundary,
            document.getElementById("box").offsetWidth - widthBoundary
          );
          let rDivTop = getRDivNumber(
            heightBoundary,
            document.getElementById("box").offsetHeight - heightBoundary
          );
          divArr[i].style.left = rDivLeft + "px";
          divArr[i].style.top = rDivTop + "px";
        }
  • 存在问题
    父级容器尺寸较小的时候可能会出现无限循环的现象,导致内存溢出

在这里插入图片描述

  • 解决办法
    这个问题暂时还没找到好的解决办法
    暂定方法:添加 maxFrequency字段,根据个人需求,判断循环次数,避免内存溢出
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值