轻松掌握屏幕坐标和窗口通信的实用技巧

2024-09-07 13:20:54 浏览数 (3)

我们通过一个实战例子来学习屏幕坐标、窗口通信

效果图

思考一个问题,上述效果图是不是多个窗口公用一个元素?

  • 显然这是不可能的,肯定是三个元素。
  • 同一个页面通过url传参的方式根据参数不同,给元素设置不同的背景。

做到上述效果图需要哪些必要条件?

  • 保证元素的位置在同一个坐标系下相同。
  • 只有在电脑屏幕下,它们的坐标系才是相同的。

涉及到的知识点

导航栏的高度计算

代码语言:javascript复制
   //获取浏览器窗口的工具栏、菜单栏和边框等元素的总高度
   function barHeight() {
       return window.outerHeight - window.innerHeight;
   }

屏幕坐标和视口坐标的转换 解析图

代码语言:javascript复制
   //将视口坐标转换为屏幕坐标
   function clientToScreen(clientX, clientY) {
       //clientX, clientY 是视口坐标
       //window.screenX 、window.screenY 是浏览器窗口左上角相对于屏幕左上角的距离
       let screenX = clientX   window.screenX;
       //注意:window.screenY 是浏览器窗口左上角相对于屏幕左上角的距离,不包括浏览器窗口的工具栏、菜单栏和边框等元素的总高度
       let screenY = clientY   window.screenY   barHeight();
       return [screenX, screenY];
   }
   //将屏幕坐标转换为视口坐标
   function screenToClient(screenX, screenY) {
       let clientX = screenX - window.screenX;
       let clientY = screenY - window.screenY - barHeight();
       return [clientX, clientY];
   }

拖拽事件

代码语言:javascript复制
  // 选择类名为.container 的元素
  const card = document.querySelector('.container');
  // 为选中的元素添加鼠标按下事件监听器
  card.onmousedown = function (e) {
  // 计算鼠标指针在卡片元素上的相对偏移量
  const x = e.pageX - card.offsetLeft;
  const y = e.pageY - card.offsetTop;

  window.onmousemove = function (e) {
      // 根据相对偏移量和鼠标移动事件的坐标计算卡片新的位置
      let cx = e.pageX - x;
      let cy = e.pageY - y;
      // 设置卡片元素的新位置
      card.style.left = cx   "px";
      card.style.top = cy   "px";
  }
  window.onmouseup = function () {
      // 释放鼠标时,取消鼠标移动和鼠标释放的事件监听器
      window.onmousemove = null;
      window.onmouseup = null;
  }
  }

窗口之间的通信

代码语言:javascript复制
  // 创建一个名为'card'的广播频道,这个频道允许不同窗口或标签之间的脚本进行通信
  const channel = new BroadcastChannel('card');
  // 将当前窗口元素位置的坐标转换为屏幕坐标
  let points = clientToScreen(cx, cy);
  // 向其他窗口传递当前窗口元素位置的屏幕坐标
  channel.postMessage(points);

  // 监听其他窗口传递过来的消息
  channel.onmessage = function (event) {
  // 使用展开运算符将事件数据转换为当前可视坐标
  let [clientX, clientY] = screenToClient(...event.data);
  // 设置元素的left属性值,将视口的X坐标应用于card元素
  card.style.left = clientX   "px"; 
  // 设置元素的top属性值,将视口的Y坐标应用于card元素
  card.style.top = clientY   "px"; 

完整代码

  • html
代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>屏幕坐标和窗口通信</title>
    <link rel="stylesheet" href="static/css/reset.css">
    <link rel="stylesheet" href="static/css/index.css">
</head>
<body>
    <div class="container"></div>
    <script src="static/js/index.js"></script>
</body>
</html>
  • css
代码语言:javascript复制
.container{
    width:300px;
    height: 300px;
    position: absolute;
}
  • js
代码语言:javascript复制

//获取浏览器窗口的工具栏、菜单栏和边框等元素的总高度
function barHeight() {
    return window.outerHeight - window.innerHeight;
}

//将视口坐标转换为屏幕坐标
function clientToScreen(clientX, clientY) {
   let screenX = clientX   window.screenX;
   let screenY = clientY   window.screenY   barHeight();
   return [screenX, screenY];
}
//将屏幕坐标转换为视口坐标
function screenToClient(screenX, screenY) {
   let clientX = screenX - window.screenX;
   let clientY = screenY - window.screenY - barHeight();
   return [clientX, clientY];
}

//创建一个名为'card'的广播频道,这个频道允许不同窗口或标签之间的脚本进行通信
const channel = new BroadcastChannel('card');

// 监听'card'频道上的消息事件
channel.onmessage = function (event) {
   // 使用展开运算符将事件数据转换为视口坐标
   let [clientX, clientY] = screenToClient(...event.data);
   // 设置元素的left属性值,将视口的X坐标应用于card元素
   card.style.left = clientX   "px"; 
   // 设置元素的top属性值,将视口的Y坐标应用于card元素
   card.style.top = clientY   "px"; 
}

// 选择类名为.container 的元素
const card = document.querySelector('.container');
// 为选中的元素添加鼠标按下事件监听器
card.onmousedown = function (e) {
  // 计算鼠标指针在卡片元素上的相对偏移量
  const x = e.pageX - card.offsetLeft;
  const y = e.pageY - card.offsetTop;

  window.onmousemove = function (e) {
    // 根据相对偏移量和鼠标移动事件的坐标计算卡片新的位置
    let cx = e.pageX - x;
    let cy = e.pageY - y;
    // 设置卡片元素的新位置
    card.style.left = cx   "px";
    card.style.top = cy   "px";

    // 将卡片当前位置的坐标转换为屏幕坐标
    let points = clientToScreen(cx, cy);
    // 通过某个数据通道发送屏幕坐标信息
    channel.postMessage(points);
  }
  window.onmouseup = function () {
    // 释放鼠标时,取消鼠标移动和鼠标释放的事件监听器
    window.onmousemove = null;
    window.onmouseup = null;
  }
}

// 定义初始化函数 init
function init() {
    // 创建一个 URL 对象,用于解析当前窗口的 URL
    let url = new URL(window.location.href);
    // 使用 URL 对象的 searchParams 属性获取 URL 中的查询字符串参数 type
    let type = url.searchParams.get("type") || "a";

    // 判断 type 是否等于 a,如果是,将 card 元素的背景颜色设置为红色
    if (type === "a") {
        card.style.background = "red";
    } 
    // 判断 type 是否等于 b,如果是,将 card 元素的背景颜色设置为绿色
    else if (type === "b") {
        card.style.background = "green";
    } 
    // 判断 type 是否等于 c,如果是,将 card 元素的背景颜色设置为蓝色
    else if (type === "c") {
        card.style.background = "blue";
    }
}

// 调用 init 函数,启动初始化逻辑
init();

0 人点赞