118 lines
5.7 KiB
HTML
118 lines
5.7 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>Document</title>
|
||
<style>
|
||
.tag-container {
|
||
position: relative; /* 作为标签绝对定位的参考容器 */
|
||
width: 800px; /* 容器宽度,可根据需求调整 */
|
||
height: 500px; /* 容器高度,可根据需求调整 */
|
||
background-color: purple; /* 容器背景,方便可视化 */
|
||
overflow: hidden; /* 防止标签超出容器(可选) */
|
||
}
|
||
|
||
.tag {
|
||
position: absolute; /* 标签绝对定位,由JS控制位置 */
|
||
padding: 5px 10px; /* 内边距,美化标签 */
|
||
border-radius: 4px; /* 圆角,美化标签 */
|
||
color: white; /* 文字颜色 */
|
||
background-color: pink; /* 标签背景色,可根据需求调整 */
|
||
white-space: nowrap; /* 防止文字换行,确保宽度由文字长度决定 */
|
||
}
|
||
|
||
/* 四种高度的标签(通过data-height区分) */
|
||
.tag[data-height="1"] {
|
||
height: 30px;
|
||
line-height: 30px;
|
||
}
|
||
.tag[data-height="2"] {
|
||
height: 40px;
|
||
line-height: 40px;
|
||
}
|
||
.tag[data-height="3"] {
|
||
height: 50px;
|
||
line-height: 50px;
|
||
}
|
||
.tag[data-height="4"] {
|
||
height: 60px;
|
||
line-height: 60px;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="tag-container">
|
||
<div class="tag" data-height="1">生日祝福</div>
|
||
<div class="tag" data-height="2">运动健身</div>
|
||
<div class="tag" data-height="3">通勤路上</div>
|
||
<div class="tag" data-height="4">影视配乐</div>
|
||
<div class="tag" data-height="1">助眠放松</div>
|
||
<div class="tag" data-height="2">派对聚会</div>
|
||
<div class="tag" data-height="3">约会浪漫</div>
|
||
<!-- 可添加更多标签 -->
|
||
</div>
|
||
|
||
<script>
|
||
document.addEventListener("DOMContentLoaded", function () {
|
||
const container = document.querySelector(".tag-container");
|
||
const tags = document.querySelectorAll(".tag");
|
||
const containerWidth = container.offsetWidth; // 容器宽度
|
||
const containerHeight = container.offsetHeight; // 容器高度
|
||
const placedTags = []; // 存储已放置标签的位置信息:{x, y, width, height}
|
||
|
||
tags.forEach((tag) => {
|
||
// 获取标签高度(从data-height属性转换)
|
||
const height = parseInt(tag.dataset.height) * 10 + 20; // 对应30/40/50/60px
|
||
const width = tag.offsetWidth; // 标签宽度(由文字内容自动计算)
|
||
let x = 0; // 初始x坐标
|
||
let y = 0; // 初始y坐标
|
||
let isPlaced = false; // 标签是否已成功放置
|
||
|
||
while (!isPlaced) {
|
||
// 检查:若当前x + 标签宽度超出容器,换行(x重置为0,y增加当前行高度)
|
||
if (x + width > containerWidth) {
|
||
x = 0;
|
||
// 计算当前行的最大高度(用于换行时的y偏移)
|
||
let maxRowHeight = 0;
|
||
placedTags.forEach((placed) => {
|
||
if (placed.y === y) {
|
||
// 属于当前行的标签
|
||
maxRowHeight = Math.max(maxRowHeight, placed.height);
|
||
}
|
||
});
|
||
y += maxRowHeight + 10; // 换行后,y增加“当前行最大高度 + 间距”
|
||
}
|
||
|
||
// 碰撞检测:检查当前(x,y)是否与已放置标签重叠
|
||
let isCollision = false;
|
||
for (let i = 0; i < placedTags.length; i++) {
|
||
const placed = placedTags[i];
|
||
// 矩形重叠判定:当前标签与已放置标签的矩形是否有交集
|
||
if (
|
||
x < placed.x + placed.width && // 当前标签左边界 < 已放置标签右边界
|
||
x + width > placed.x && // 当前标签右边界 > 已放置标签左边界
|
||
y < placed.y + placed.height && // 当前标签上边界 < 已放置标签下边界
|
||
y + height > placed.y // 当前标签下边界 > 已放置标签上边界
|
||
) {
|
||
isCollision = true;
|
||
// 碰撞后,将x移到“已放置标签的右边界 + 间距”,尝试下一个位置
|
||
x = placed.x + placed.width + 10;
|
||
break; // 跳出循环,重新检查新x是否合法
|
||
}
|
||
}
|
||
|
||
// 无碰撞:设置标签位置,并记录到已放置数组
|
||
if (!isCollision) {
|
||
tag.style.left = `${x}px`;
|
||
tag.style.top = `${y}px`;
|
||
placedTags.push({ x, y, width, height });
|
||
isPlaced = true;
|
||
}
|
||
}
|
||
});
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|