You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

362 lines
13 KiB
HTML

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>DOM元素框选工具</title>
<style>
body {
margin: 0;
padding: 20px;
font-family: Arial, sans-serif;
background-color: #f5f5f5;
}
#container {
position: relative;
width: 100%;
height: 80vh;
border: 2px solid #333;
background-color: white;
overflow: hidden;
}
.selectable-element {
position: absolute;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #ccc;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transition: all 0.2s ease;
}
.selectable-element:hover {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
transform: scale(1.02);
}
.selectable-element.selected {
border: 2px solid #007bff;
box-shadow: 0 0 10px rgba(0, 123, 255, 0.5);
z-index: 10;
}
#selection-box {
position: absolute;
border: 2px dashed #007bff;
background-color: rgba(0, 123, 255, 0.1);
pointer-events: none;
display: none;
}
#result {
margin-top: 20px;
padding: 15px;
background-color: #e9ecef;
border-radius: 5px;
min-height: 100px;
}
button {
margin: 5px;
padding: 10px 15px;
background-color: #007bff;
color: white;
border: none;
border-radius: 3px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
h1 {
color: #333;
}
</style>
</head>
<body>
<h1>DOM元素框选工具</h1>
<div id="container">
<!-- 可选择的元素 -->
<div
class="selectable-element"
style="width: 100px; height: 60px; top: 50px; left: 50px; background-color: #ff6b6b"
>
图片1
</div>
<div
class="selectable-element"
style="width: 120px; height: 80px; top: 150px; left: 200px; background-color: #4ecdc4"
>
按钮1
</div>
<div
class="selectable-element"
style="width: 150px; height: 70px; top: 300px; left: 100px; background-color: #45b7d1"
>
文本框
</div>
<div
class="selectable-element"
style="width: 80px; height: 80px; top: 200px; left: 400px; background-color: #96ceb4"
>
图片2
</div>
<div
class="selectable-element"
style="width: 100px; height: 50px; top: 100px; left: 500px; background-color: #feca57"
>
按钮2
</div>
<div
class="selectable-element"
style="width: 130px; height: 90px; top: 350px; left: 400px; background-color: #ff9ff3"
>
文本区域
</div>
<div
class="selectable-element"
style="width: 90px; height: 90px; top: 50px; left: 600px; background-color: #54a0ff"
>
图标
</div>
<div
class="selectable-element"
style="width: 110px; height: 60px; top: 250px; left: 650px; background-color: #5f27cd"
>
标签
</div>
<div
class="selectable-element"
style="width: 140px; height: 80px; top: 150px; left: 750px; background-color: #00d2d3"
>
输入框
</div>
<div
class="selectable-element"
style="width: 100px; height: 100px; top: 300px; left: 700px; background-color: #ff6348"
>
按钮3
</div>
<!-- 框选框 -->
<div id="selection-box"></div>
</div>
<div>
<button onclick="clearSelection()">清除选择</button>
<button onclick="getSelectedElements()">获取选中元素</button>
</div>
<div id="result">
<h3>选中元素列表:</h3>
<p id="selected-list">暂无选中元素</p>
</div>
<script>
let isSelecting = false;
let startX, startY;
let selectionBox = document.getElementById('selection-box');
let container = document.getElementById('container');
let elements = document.querySelectorAll('.selectable-element');
// 鼠标按下事件
container.addEventListener('mousedown', function (e) {
// 如果点击的是元素本身,则不进行框选
if (e.target.classList.contains('selectable-element')) {
return;
}
isSelecting = true;
// 获取相对于容器的坐标
const rect = container.getBoundingClientRect();
startX = e.clientX - rect.left;
startY = e.clientY - rect.top;
// 设置框选框的位置和大小
selectionBox.style.left = startX + 'px';
selectionBox.style.top = startY + 'px';
selectionBox.style.width = '0px';
selectionBox.style.height = '0px';
selectionBox.style.display = 'block'; // 防止拖拽时选择文字
e.preventDefault();
});
// 鼠标移动事件
container.addEventListener('mousemove', function (e) {
if (!isSelecting) return;
const rect = container.getBoundingClientRect();
const currentX = e.clientX - rect.left;
const currentY = e.clientY - rect.top;
// 计算框选框的宽度和高度
const width = Math.abs(currentX - startX);
const height = Math.abs(currentY - startY);
// 确定框选框的左上角位置
const left = Math.min(startX, currentX);
const top = Math.min(startY, currentY);
// 更新框选框的样式
selectionBox.style.left = left + 'px';
selectionBox.style.top = top + 'px';
selectionBox.style.width = width + 'px';
selectionBox.style.height = height + 'px';
});
// 鼠标释放事件
container.addEventListener('mouseup', function (e) {
if (!isSelecting) return;
isSelecting = false;
// 获取框选范围(在隐藏之前)
const containerRect = container.getBoundingClientRect();
const selectionLeft = parseFloat(selectionBox.style.left);
const selectionTop = parseFloat(selectionBox.style.top);
const selectionWidth = parseFloat(selectionBox.style.width);
const selectionHeight = parseFloat(selectionBox.style.height);
// 修复确保最小尺寸为1像素避免0值问题
const finalWidth = Math.max(selectionWidth, 1);
const finalHeight = Math.max(selectionHeight, 1);
const finalLeft = selectionLeft;
const finalTop = selectionTop;
console.log('Selection box info:', {
left: finalLeft,
top: finalTop,
width: finalWidth,
height: finalHeight,
containerRect: containerRect,
});
// 隐藏框选框
selectionBox.style.display = 'none';
// 检查哪些元素在框选范围内
checkSelection(finalLeft, finalTop, finalWidth, finalHeight);
});
// 检查元素是否在框选范围内
function checkSelection(left, top, width, height) {
console.log('Checking selection:', { left, top, width, height });
const selectedElements = [];
elements.forEach((element) => {
const elementRect = element.getBoundingClientRect();
const containerRect = container.getBoundingClientRect();
// 转换为相对于容器的坐标
const elementLeft = elementRect.left - containerRect.left;
const elementTop = elementRect.top - containerRect.top;
const elementWidth = elementRect.width;
const elementHeight = elementRect.height;
console.log('Element info:', {
text: element.textContent,
left: elementLeft,
top: elementTop,
width: elementWidth,
height: elementHeight,
});
// 矩形相交检测算法
// 两个矩形相交的条件是在x轴和y轴上都有重叠
const xOverlap = elementLeft < left + width && elementLeft + elementWidth > left;
const yOverlap = elementTop < top + height && elementTop + elementHeight > top;
console.log('Overlap check:', {
xOverlap,
yOverlap,
condition: xOverlap && yOverlap,
});
if (xOverlap && yOverlap) {
selectedElements.push(element);
}
});
console.log('Selected elements count:', selectedElements.length);
// 标记选中的元素
markSelectedElements(selectedElements);
// 显示结果
displayResults(selectedElements);
}
// 标记选中的元素
function markSelectedElements(elements) {
// 先清除所有已选中的标记
document.querySelectorAll('.selectable-element.selected').forEach((el) => {
el.classList.remove('selected');
});
// 给新选中的元素添加标记
elements.forEach((element) => {
element.classList.add('selected');
});
}
// 显示结果
function displayResults(elements) {
const resultElement = document.getElementById('selected-list');
if (elements.length === 0) {
resultElement.innerHTML = '没有选中任何元素';
return;
}
let html = '<ul>';
elements.forEach((element, index) => {
html += `<li>${index + 1}. ${element.textContent || '未知元素'}</li>`;
});
html += '</ul>';
resultElement.innerHTML = html;
}
// 清除选择
function clearSelection() {
document.querySelectorAll('.selectable-element.selected').forEach((el) => {
el.classList.remove('selected');
});
document.getElementById('selected-list').innerHTML = '暂无选中元素';
}
// 获取选中元素
function getSelectedElements() {
const selectedElements = document.querySelectorAll('.selectable-element.selected');
const elementsArray = Array.from(selectedElements);
displayResults(elementsArray);
}
// 添加鼠标离开容器时的处理,防止拖拽时鼠标移出容器导致的问题
document.addEventListener('mouseleave', function (e) {
if (isSelecting && e.target === container) {
isSelecting = false;
selectionBox.style.display = 'none';
}
});
// 添加document mouseup事件防止鼠标在容器外释放时的问题
document.addEventListener('mouseup', function (e) {
if (isSelecting) {
isSelecting = false;
selectionBox.style.display = 'none';
}
});
</script>
</body>
</html>