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字段,根据个人需求,判断循环次数,避免内存溢出
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Vue中实现在某一区域中多个元素随机定位显示且不重叠的一种比较简单的方法是使用CSS中的`position: absolute`属性和JavaScript中的随机数生成函数。具体实现步骤如下: 1. 在Vue的模板中,定义一个容器元素,设置其样式为`position: relative`,表示其内部的元素都是以该容器为基准进行绝对定位。 ```html <template> <div class="container"> <div class="box" v-for="(item, index) in items" :key="index">{{ item }}</div> </div> </template> <style> .container { position: relative; width: 500px; height: 300px; border: 1px solid #ccc; } .box { position: absolute; width: 50px; height: 50px; background-color: #f00; color: #fff; text-align: center; line-height: 50px; } </style> ``` 2. 在Vue的`data`中定义一个数组`items`,存储要显示的元素。 ```javascript export default { data() { return { items: ['A', 'B', 'C', 'D', 'E'] } } } ``` 3. 在Vue的`mounted`生命周期函数中,使用JavaScript中的`Math.random()`函数生成随机的`left`和`top`值,将每个元素进行定位,并检测是否与其他元素重叠,若重叠则重新生成随机位置,直到不重叠为止。 ```javascript export default { mounted() { const boxes = this.$el.querySelectorAll('.box') const containerRect = this.$el.getBoundingClientRect() const boxRects = Array.from(boxes).map(box => box.getBoundingClientRect()) for (let i = 0; i < boxes.length; i++) { let left = Math.floor(Math.random() * (containerRect.width - boxRects[i].width)) let top = Math.floor(Math.random() * (containerRect.height - boxRects[i].height)) while (isOverlap(left, top, i, boxRects)) { left = Math.floor(Math.random() * (containerRect.width - boxRects[i].width)) top = Math.floor(Math.random() * (containerRect.height - boxRects[i].height)) } boxes[i].style.left = `${left}px` boxes[i].style.top = `${top}px` } function isOverlap(left, top, index, rects) { for (let i = 0; i < index; i++) { if (left + rects[index].width > rects[i].left && left < rects[i].left + rects[i].width && top + rects[index].height > rects[i].top && top < rects[i].top + rects[i].height) { return true } } return false } } } ``` 4. 在判断是否重叠的函数`isOverlap`中,通过比较当前元素的位置和之前元素的位置,判断是否重叠,若重叠则返回`true`,否则返回`false`。 这样,就实现了在Vue中实现在某一区域中多个元素随机定位显示且不重叠的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值