You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在移动端/小屏幕避免created钩子创建的随机定位div重叠?

解决Vue中随机定位圆形元素在移动端/窗口缩小时的重叠问题

核心问题拆解

  • created 钩子执行时机早于DOM挂载,无法获取容器和元素的实际渲染尺寸,初始位置计算基于默认值,适配移动端时尺寸变化后位置失效。
  • 窗口尺寸变化时未重新计算元素位置,导致原有位置在新尺寸空间下出现重叠。

解决方案步骤

  1. 替换钩子时机:用 mounted 钩子替代 created,此时DOM已完成挂载,可获取到容器和元素的真实尺寸。
  2. 监听窗口 resize 事件:在窗口尺寸变化时,重新计算所有元素的随机位置,避免重叠。
  3. 封装碰撞检测工具函数:基于当前容器和元素的实时尺寸,生成不重叠的随机坐标。
  4. 配合媒体查询:确保容器和元素的尺寸在不同屏幕下适配,为位置计算提供正确的基础尺寸。

完整组件代码示例

<template>
  <div class="circle-container" ref="container">
    <div
      v-for="(circle, index) in circles"
      :key="index"
      class="circle"
      :style="{ left: `${circle.x}px`, top: `${circle.y}px` }"
    ></div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      circles: [],
      circleCount: 10, // 圆形元素数量
      resizeTimer: null
    };
  },
  mounted() {
    // 初始化生成圆形位置
    this.generateCircles();
    // 监听窗口 resize 事件
    window.addEventListener('resize', this.handleResize);
  },
  beforeUnmount() {
    // 移除监听,避免内存泄漏
    window.removeEventListener('resize', this.handleResize);
    if (this.resizeTimer) clearTimeout(this.resizeTimer);
  },
  methods: {
    // 防抖处理 resize 事件,避免频繁触发
    handleResize() {
      clearTimeout(this.resizeTimer);
      this.resizeTimer = setTimeout(() => {
        this.generateCircles();
      }, 200);
    },
    // 生成所有不重叠的圆形元素位置
    generateCircles() {
      const container = this.$refs.container;
      if (!container) return;

      const containerWidth = container.offsetWidth;
      const containerHeight = container.offsetHeight;
      // 获取圆形元素的实时尺寸(由媒体查询控制)
      const circleSize = parseInt(getComputedStyle(document.querySelector('.circle')).width);
      const circles = [];

      for (let i = 0; i < this.circleCount; i++) {
        let newCircle;
        // 循环生成直到找到不重叠的位置
        do {
          newCircle = this.getRandomCircle(containerWidth, containerHeight, circleSize);
        } while (this.isOverlap(newCircle, circles, circleSize));
        circles.push(newCircle);
      }

      this.circles = circles;
    },
    // 生成单个圆形的随机坐标
    getRandomCircle(containerWidth, containerHeight, circleSize) {
      return {
        x: Math.floor(Math.random() * (containerWidth - circleSize)),
        y: Math.floor(Math.random() * (containerHeight - circleSize))
      };
    },
    // 碰撞检测:判断新生成的圆形是否与已有圆形重叠
    isOverlap(newCircle, existingCircles, circleSize) {
      const radius = circleSize / 2;
      const newCenterX = newCircle.x + radius;
      const newCenterY = newCircle.y + radius;

      return existingCircles.some(circle => {
        const existingCenterX = circle.x + radius;
        const existingCenterY = circle.y + radius;
        // 计算两个圆心的距离
        const distance = Math.sqrt(
          Math.pow(newCenterX - existingCenterX, 2) + Math.pow(newCenterY - existingCenterY, 2)
        );
        // 距离小于两个半径之和则重叠
        return distance < circleSize;
      });
    }
  }
};
</script>

<style scoped>
.circle-container {
  width: 100%;
  height: 80vh;
  position: relative;
  overflow: hidden;
  border: 1px solid #eee;
}

.circle {
  position: absolute;
  border-radius: 50%;
  background-color: #42b983;
}

/* 媒体查询控制圆形尺寸 */
@media (min-width: 768px) {
  .circle {
    width: 60px;
    height: 60px;
  }
}

@media (max-width: 767px) {
  .circle {
    width: 40px;
    height: 40px;
  }
}
</style>

代码关键点说明

  • mounted 钩子:确保DOM挂载后再获取容器尺寸,初始计算的位置基于真实渲染尺寸。
  • 防抖的 resize 处理:避免窗口拖拽时频繁触发位置计算,提升性能。
  • 碰撞检测逻辑:通过计算圆心距离判断是否重叠,确保所有元素在当前容器尺寸下无重叠。
  • 媒体查询配合:不同屏幕下的圆形尺寸是位置计算的基础,确保坐标适配当前元素大小。

内容的提问来源于stack exchange,提问作者parsecer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 05:07:43