- Published on
实现多窗口拖拽卡片的示例
- Authors
- Name
- Tian Haipeng
1. HTML 结构
我们首先创建一个简单的 HTML 页面,其中包含一张图片作为拖拽卡片。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Multi-window Drag Card</title>
<style>
.card {
width: 200px;
height: 400px;
position: absolute;
}
</style>
</head>
<body>
<img class="card" src="./Q.jpg" alt=""/>
<script>
</script>
</body>
</html>
2. 初始化图片源
我们可以从 URL 参数中获取图片类型,并相应地设置卡片的图片源。
function init() {
const url = new URL(location.href);
const type = url.searchParams.get('type') || 'Q';
card.src = `./${type}.jpg`;
}
init();
3. 禁用默认拖拽行为
为了防止图片被浏览器默认处理为拖拽对象,我们需要禁用图片的默认拖拽行为。
const card = document.querySelector('.card');
// 阻止图片的默认拖拽行为
card.ondragstart = (e) => {
e.preventDefault();
}
4. 实现拖拽功能
我们需要实现拖拽的逻辑,使得卡片能够跟随鼠标移动。同时,我们还要将卡片的新位置发送到其他窗口。
card.onmousedown = (e) => {
let x = e.pageX - card.offsetLeft;
let y = e.pageY - card.offsetTop;
window.onmousemove = function (e) {
const cx = e.pageX - x;
const cy = e.pageY - y;
card.style.left = cx + 'px';
card.style.top = cy + 'px';
const points = clientToScreen(cx, cy);
channel.postMessage(points);
}
window.onmouseup = function () {
window.onmousemove = null;
window.onmouseup = null;
}
}
5. 计算屏幕位置
为了在不同的窗口之间同步拖拽位置,我们需要将鼠标的位置从客户端坐标转换为屏幕坐标,并且反向转换。这是因为浏览器的 screenX
和 screenY
属性提供了相对于屏幕的坐标,而 clientX
和 clientY
提供了相对于客户端的坐标。
function barHeight() {
return window.outerHeight - window.innerHeight;
}
function clientToScreen(clientX, clientY) {
const screenX = clientX + window.screenX;
const screenY = clientY + window.screenY + barHeight();
return [screenX, screenY];
}
function screenToClient(screenX, screenY) {
const clientX = screenX - window.screenX;
const clientY = screenY - window.screenY - barHeight();
return [clientX, clientY];
}
6. 使用 BroadcastChannel 实现跨窗口通信
BroadcastChannel
API 允许我们在多个窗口之间发送和接收消息。我们将使用它来同步拖拽卡片的位置。
const channel = new BroadcastChannel('card');
channel.onmessage = (e) => {
console.log(e.data);
const [x, y] = screenToClient(...e.data);
card.style.left = x + 'px';
card.style.top = y + 'px';
}
总结
通过以上步骤,就成功实现了一个多窗口拖拽卡片的示例。这个例子展示了如何使用 BroadcastChannel
API 在多个窗口之间同步拖拽操作,并使用 JavaScript 处理鼠标事件和坐标转换。
以下是完整的代码:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Multi-window Drag Card</title>
<style>
.card {
width: 200px;
height: 400px;
position: absolute;
}
</style>
</head>
<body>
<img class="card" src="./Q.jpg" alt=""/>
<script>
const card = document.querySelector('.card');
// 阻止图片的默认拖拽行为
card.ondragstart = (e) => {
e.preventDefault();
}
function barHeight() {
return window.outerHeight - window.innerHeight;
}
function clientToScreen(clientX, clientY) {
const screenX = clientX + window.screenX;
const screenY = clientY + window.screenY + barHeight();
return [screenX, screenY];
}
function screenToClient(screenX, screenY) {
const clientX = screenX - window.screenX;
const clientY = screenY - window.screenY - barHeight();
return [clientX, clientY];
}
const channel = new BroadcastChannel('card');
channel.onmessage = (e) => {
console.log(e.data);
const [x, y] = screenToClient(...e.data);
card.style.left = x + 'px';
card.style.top = y + 'px';
}
card.onmousedown = (e) => {
let x = e.pageX - card.offsetLeft;
let y = e.pageY - card.offsetTop;
window.onmousemove = function (e) {
const cx = e.pageX - x;
const cy = e.pageY - y;
card.style.left = cx + 'px';
card.style.top = cy + 'px';
const points = clientToScreen(cx, cy);
channel.postMessage(points);
}
window.onmouseup = function () {
window.onmousemove = null;
window.onmouseup = null;
}
}
function init() {
const url = new URL(location.href);
const type = url.searchParams.get('type') || 'Q';
card.src = `./${type}.jpg`;
}
init();
</script>
</body>
</html>