最近有个海外的大牛做的量子球在浏览器窗口之间的交互很是惊艳,在前端圈子非常火爆。和朋友探讨涉及到的技术细节,其中主要还是利用到了窗口之间的通信,同时需要专递的信息就是量子球在使用canvas绘制时的各种坐标数据信息。下面是自己实现的一个非常简单的demo。
index.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>
body {
position: relative;
margin: 0;
padding: 0;
overflow: hidden;
}
.rocket {
position: absolute;
top: 0;
left: 0;
cursor: pointer;
}
</style>
</head>
<img>
<img class="rocket" src="./rocket.png"></img>
<script src="index.js"></script>
</body>
</html>
index.js
; (function () {
// 获取火箭图片dom
const rocket = document.querySelector('.rocket')
let isDragging = false // 是否处于拖拽状态
let dx = 0 // 点击位置距火箭图片左边缘的距离
let dy = 0 // 点击位置距火箭图片上边缘的距离
const channel = new BroadcastChannel('rocket') // 窗口信息交互广播事件
channel.onmessage = (e) => {
const [clientX, clientY] = screenToClient(e.data)
rocket.style.left = clientX + 'px'
rocket.style.top = clientY + 'px'
}
/**
* 视口坐标转屏幕坐标
* @param {*} param0
* @returns
*/
function clientToScreen([clientX, clientY]) {
const barHeight = window.outerHeight - window.innerHeight // 浏览器工具栏高度
const screenX = window.screenX + clientX
const screenY = window.screenY + clientY + barHeight
return [screenX, screenY]
}
/**
* 屏幕坐标转视口坐标
* @param {*} param0
* @returns
*/
function screenToClient([screenX, screenY]) {
const barHeight = window.outerHeight - window.innerHeight // 浏览器工具栏高度
const clientX = screenX - window.screenX
const clientY = screenY - window.screenY - barHeight
return [clientX, clientY]
}
/**
* 火箭图片点下事件
* @param {*} e
*/
rocket.onmousedown = (e) => {
e.preventDefault()
isDragging = true
dx = e.pageX - rocket.offsetLeft
dy = e.pageY - rocket.offsetTop
}
/**
* 火箭图片在视口中移动事件
* @param {*} e
* @returns
*/
window.onmousemove = (e) => {
if (!isDragging) {
return
}
const targetX = e.pageX - dx
const targetY = e.pageY - dy
rocket.style.left = targetX + 'px'
rocket.style.top = targetY + 'px'
const screentPoints = clientToScreen([targetX, targetY])
channel.postMessage(screentPoints)
}
/**
* 火箭图片点击取消事件
*/
rocket.onmouseup = () => {
isDragging = false
}
})()
rocket.png