# html--0.魔术卡片

2024-01-19 11.30.28

# 核心原理:屏幕坐标和窗口通信

image-20230919004357317

# 元素移动

# 元素在浏览器中坐标

元素左上角在浏览器中的坐标

offsetLeft offsetTop

const card = document.querySelector('.card');
card.offsetLeft;
card.offsetTop;

# 鼠标在浏览器中坐标

获取被点击元素,鼠标距离浏览器窗口的坐标

pageX pageY

const card = document.querySelector('.card');
card.onmousedown = (e) => {
    //鼠标点击位置:浏览器窗口坐标
    e.pageX
    e.pageY
}

# 计算鼠标在元素中坐标

鼠标在元素中坐标 = 浏览器坐标 - 元素坐标

const card = document.querySelector('.card');
card.onmousedown = (e) => {
    //浏览器窗口中的坐标
    let x = e.pageX - card.offsetLeft;
    let y = e.pageY - card.offsetTop;
}

# 元素移动-->计算元素在浏览器中坐标

元素移动时

改变元素的绝对定位:left、top属性

核心原理:元素坐标 = 鼠标浏览器坐标 - 鼠标元素中坐标

具体步骤:

(1)鼠标按下时: 计算出:鼠标在元素中的坐标

(2)鼠标移动时:

​ 元素坐标 = 鼠标浏览器坐标 - 鼠标在元素中坐标

(3)鼠标抬起

​ 取消:按下、移动 的事件

card.onmousedown = (e) => {
    //浏览器窗口中的坐标
    let x = e.pageX - card.offsetLeft;
    let y = e.pageY - card.offsetTop;

    window.onmousemove = (e) => {
        const cx = e.pageX - x;
        const cy = e.pageY - y;
        card.style.left = cx + 'px';
        card.style.top = cy + 'px';
    };

    window.onmouseup = () => {
        window.onmousemove = null;
        window.onmouseup = null;
    };
}

# 浏览器在屏幕中坐标

image-20240119110348061

获取浏览器窗口在屏幕中的坐标

// api一
window.screenX
window.screenY

// api二
window.screenLeft
window.screenTop

窗口可视区域大小

var windowInnerWidth = window.innerWidth;
var windowInnerHeight = window.innerHeight;
console.log("浏览器窗口内部宽度" + windowInnerWidth);
console.log("浏览器窗口内部高度" + windowInnerHeight);

var windowWidth = window.outerWidth;
var windowHeight = window.outerHeight;
console.log("浏览器窗口宽度:" + windowWidth);
console.log("浏览器窗口高度:" + windowHeight);

# 元素浏览器坐标<==>元素屏幕坐标

image-20240119111225098

元素浏览器坐标==>元素屏幕坐标

元素_屏幕_X = 元素_浏览器_X + 浏览器_屏幕_X

元素_屏幕_Y = 元素_浏览器_Y + 浏览器_屏幕_Y + 工具栏高度 推导出==》 元素_屏幕_Y = 元素_浏览器_Y + 浏览器_屏幕_Y + (浏览器_外高度 - 浏览器_内高度)

function getScreenPoint(clientX, clientY) {
    //元素_屏幕_X = 元素_浏览器_X + 浏览器_屏幕_X
    const screenX = clientX + window.screenX;
    //元素_屏幕_Y = 元素_浏览器_Y + 浏览器_屏幕_Y + (浏览器_外高度 - 浏览器_内高度)
    const screenY = clientY + window.screenY + (window.outerHeight - window.innerHeight);
    return [screenX, screenY];
}

元素浏览器坐标<==元素屏幕坐标

同理换算可得

元素_浏览器_X = 元素_屏幕_X - 浏览器_屏幕_X

元素_浏览器_Y = 元素_屏幕_Y - 浏览器_屏幕_Y - (浏览器_外高度 - 浏览器_内高度)

function getClientPoint(screenX, screenY) {
    //元素_浏览器_X = 元素_屏幕_X - 浏览器_屏幕_X
    const clientX = screenX - window.screenX;
    //元素_浏览器_Y = 元素_屏幕_Y - 浏览器_屏幕_Y - (浏览器_外高度 - 浏览器_内高度)
    const clientY = screenY - window.screenY - (window.outerHeight - window.innerHeight);
    return [clientX, clientY];
}

# 窗口通信

//订阅|创建
const channel = new BroadcastChannel('card');

//发送
channel.postMessage(getScreenPoint(cx, cy));
//接收
channel.onmessage = (e) => {
    const [cx, cy] = getClientPoint(...e.data);
    card.style.left = cx + 'px';
    card.style.top = cy + 'px';
}

# 代码实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <link rel="stylesheet" href="./style.css">
    <style>
        .card {
            background-color: red;
            width: 100px;
            height: 100px;
            border: 1px solid #000000;
            display: flex;
            position: absolute;
            left: 0px;
            top: 0px;
        }
    </style>
</head>
<body>

<!--卡片-->
<div class="card"></div>

<!--实现-->
<script src="./index.js"></script>
</body>
</html>
const card = document.querySelector('.card');

card.onmousedown = (e) => {
    //浏览器窗口中的坐标
    let x = e.pageX - card.offsetLeft;
    let y = e.pageY - card.offsetTop;

    window.onmousemove = (e) => {
        const cx = e.pageX - x;
        const cy = e.pageY - y;
        card.style.left = cx + 'px';
        card.style.top = cy + 'px';

        channel.postMessage(getScreenPoint(cx, cy));
    };

    window.onmouseup = () => {
        window.onmousemove = null;
        window.onmouseup = null;
    };
}

function init() {
    if (location.search.includes('hidden')) {
        card.style.left = '-1000px';
    }
}

init();

function getClientPoint(screenX, screenY) {
    const clientX = screenX - window.screenX;
    const clientY = screenY - window.screenY - (window.outerHeight - window.innerHeight);
    return [clientX, clientY];
}

function getScreenPoint(clientX, clientY) {
    const screenX = clientX + window.screenX;
    const screenY = clientY + window.screenY +  (window.outerHeight - window.innerHeight);
    return [screenX, screenY];
}

const channel = new BroadcastChannel('card');



channel.onmessage = (e) => {
    const [cx, cy] = getClientPoint(...e.data);
    card.style.left = cx + 'px';
    card.style.top = cy + 'px';
}

更新时间: 2024年1月19日星期五中午11点37分