首页 > 其他分享 >记录--浏览器跨标签星球火了,简单探究一下实现原理

记录--浏览器跨标签星球火了,简单探究一下实现原理

时间:2023-11-27 18:38:39浏览次数:41  
标签:style 浏览器 -- px window 坐标 cardDom 星球 const

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

一、前言

最近 推特上 一位懂设计和写代码的大神一个两个浏览器之间 星球粒子交互的动画火了, 让人看了大呼脑洞大开, 浏览器竟然还能这么玩!!!

准备自己也搞搞玩一下

二、实现

原作者的粒子动画非常炫酷, 但是不是我们本文重点, 我们通过一个元素在不同窗口的拖拽实现一个可以变幻的例子来学习一下原理, 后续在实现一个稍微复杂的多窗口的小游戏。关于粒子动画的内容,有兴趣的小伙伴可以自己实现

其实实现类似的功能需要的难点并不多,不在乎以下几个步骤

  • 1、 屏幕坐标和窗口坐标转换
  • 2、 跨标签通讯

1、 先来看第一个点, 获取屏幕坐标与窗口坐标

// 屏幕坐标转换为窗口坐标
const screenToClient = (screenX, screenY) => {
  const clienX = screenX - window.screenX;
  const clienY = screenY - window.screenY - barHeight();
  return [clienX, clienY];
};

// 窗口坐标转换为屏幕坐标
const clientToScreen = (clienX, clienY) => {
  const screenX = clienX + window.screenX;
  const screenY = clienY + window.screenY + barHeight();
  return [screenX, screenY];
};

我们先简单实现一个卡片, 通过url上面传递颜色值, 设置定位

在卡片本上设置上点击拖动等事件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>跨标签通讯</title>
  </head>
  <style>
    .card {
      width: 300px;
      height: 300px;
      background-color: #f00;
      position: fixed;
      top: 100px;
      left: 100px;
    }
  </style>
  <body>
    跨标签通讯
    <div class="card">card</div>
  </body>
  <script>
    const barHeight = () => window.outerHeight - window.innerHeight;
    const cardDom = document.querySelector(".card");
    cardDom.style.top = 100 + "px";
    cardDom.style.left = 100 + "px";
    cardDom.style.background =
      new URLSearchParams(window.location.search).get("color") || "red";

    window.onload = function () {
      cardDom.onmousedown = function (e) {
        cardDom.style.cursor = "pointer";
        let x = e.pageX - cardDom.offsetLeft;
        let y = e.pageY - cardDom.offsetTop;
        window.onmousemove = function (e) {
          cardDom.style.left = e.clientX - x + "px";
          cardDom.style.top = e.clientY - y + "px";
          // 发送消息
          const clientCoordinateX = e.clientX - x;
          const clientCoordinateY = e.clientY - y;
          const ScreenCoordinate = clientToScreen(
            clientCoordinateX,
            clientCoordinateY
          );
          sendMessage(ScreenCoordinate);
        };
        window.onmouseup = function () {
          window.onmousemove = null;
          window.onmouseup = null;
          cardDom.style.cursor = "unset";
        };
      };
    };
  </script>
</html>

2、 跨标签传输

单个元素的拖动就实现了, 很简单, 如何让其他标签的元素也能同步进行, 需要实现跨标签方案了, 可以参考该文章- 跨标签页通信的8种方式

我们就选择第一种,使用 BroadCast Channel, 使用也很简单

// 创建 Broadcast Channel
const channel = new BroadcastChannel("myChannel");
// 监听消息
channel.onmessage = (event) => {
  // 处理接收到的消息
  console.log('接收',event)
};
// 发送消息
const sendMessage = (message) => {
  channel.postMessage(message);
};
只需要在移动时发送消息, 再其他标签页就可以接收到值了, 现在关键的就是收到发送的坐标点后, 如何处理, 其实关键就是要让几个窗口的卡片位置转化到同一个纬度, 让其再超出浏览器的时候,再另一个窗口的同一个位置出现, 所以就需要将窗口坐标转化成屏幕坐标,发送给其他窗口后, 再转化成窗口坐标进行渲染即可
// 鼠标移动发送消息的时候,窗口坐标转化成屏幕坐标
window.onmousemove = function (e) {
  cardDom.style.left = e.clientX - x + "px";
  cardDom.style.top = e.clientY - y + "px";
  const clientCoordinateX = e.clientX - x;
  const clientCoordinateY = e.clientY - y;
  const ScreenCoordinate = clientToScreen(
    clientCoordinateX,
    clientCoordinateY
  );
sendMessage(ScreenCoordinate);
  
// 接收消息的时候,屏幕坐标转化成窗口坐标 
channel.onmessage = (event) => {
  // 处理接收到的消息
  const [clienX, clienY] = screenToClient(...event.data);
  // 不同窗口的卡片要在同一个位置, 要放到同一个坐标系下面,保持屏幕坐标一致
  cardDom.style.left = clienX + "px";
  cardDom.style.top = clienY + "px";
};

完整代码,在最下面

三、总结

本文通过移动一个简单的图形, 在不同浏览器之间穿梭变换, 初步体验了多个浏览器之间如何进行交互, 通过拖拽元素,通过跨标签的通讯, 将当前窗口元素的位置进行发送, 另一个窗口进行实时接收, 然后通过屏幕坐标和窗口坐标进行转换, 就能实现,从一个浏览器拖动到另一个浏览器时, 变化元素颜色的功能了, 当然变化背景色只是举例子, 你也可以变化扑克牌, 变化照片, 这样看起来像变魔术一样,非常神奇,看似浏览器不同标签之间没有联系,当以这种方式产生联系后, 就会产生很多不可思议的神奇事情。 就像国外大神的多标签页的两个星球粒子, 产生吸引 融合的效果。原理其实是一样的。

后续前瞻

在通过小demo的学习,知道多浏览器的玩法后, 接下来的我们会实现一个更有意思的小游戏,通过浏览器化身一个小木棒, 接小球游戏, 先看一下 gif, 接下来的文章会写具体实现

 

传送门

标签:style,浏览器,--,px,window,坐标,cardDom,星球,const
From: https://www.cnblogs.com/smileZAZ/p/17860076.html

相关文章

  • Linux进程学习
    学习 Linux 进程管理可以帮助我们深入了解操作系统的核心功能,并提高系统管理和故障排除的能力。以下是一些学习 Linux 进程管理的心得:1. 理解进程的概念和状态:进程是正在运行的程序的实例,它具有不同的状态,如运行、等待、停止等。了解这些状态以及它们之间的转换对于理解进程......
  • 10月20日每日学习
    今天写了一下人机交互的第二个实验,用C#写一个管理系统界面大体就是这样,是一个很简单的系统......
  • linux常用指令(top,ps-ef,htop)
    1、查看已经运行的任务:top:实时显示系统的运行状态,包括运行的进程、CPU使用率、内存使用情况 ps-ef:列出当前系统中所有的进程,包括进程的PID、父进程ID、CPU使用率、内存使用 htop:列出当前系统中所有的进程,包括进程的PID、父进程ID、CPU使用率、内存使用......
  • Map和模糊查询
    Map在UserDao接口中intAddUser2(Map<String,Object>map);UserMapper.xml<insertid="AddUser2"parameterType="map">insertintouser.use1(id,name,pwd)values(#{UserId},#{UserName},#{password});</insert>......
  • python--条件
    Task4条件条件if语句上边是if语句执行的一个基本流程下边现在有一个简单的例子deff(x):print("A",end='')ifx==0:print("B",end='')print("C",end='')print("D")f(1) #运行结果是AD......
  • D. Small GCD
    D.SmallGCDLet$a$,$b$,and$c$beintegers.Wedefinefunction$f(a,b,c)$asfollows:Orderthenumbers$a$,$b$,$c$insuchawaythat$a\leb\lec$.Thenreturn$\gcd(a,b)$,where$\gcd(a,b)$denotesthegreatestcommondivisor(GCD)ofi......
  • 更新 Kubernetes 集群中 Argo CD 的服务类型为 NodePort失败
    这个问题是我再做项目的时候要开区argoCD时并链接时端口开区不了kubectlpatchsvcargocd-server-nargocd-p'{"spec":{"type":"NodePort"}}'service/argocd-serverpatched(nochange)发现这样的问题这个问题我是换了一个思路是直接来做以刻kubernetes的yaml文件并且......
  • P7626 [COCI2011-2012#1] MATRIX( 普及/提高− ) 题解
    题目传送门思路:首先思考暴力,\(O(n^4)\)的时间复杂度,不行。那么我们这里就要运用到一点前缀和的知识了。我们可以用前缀和对两条对角线进行计数。每个点有两个对角线运算。差不多是\(O(n^2)\)到\(O(n^3)\)的时间复杂度。而\(n\leq400\)稳过。Code:#include<bits/stdc......
  • 11月23日每日学习
    今天写的是flash的大作业<!DOCTYPEhtml><html><head><metahttp-equiv="content-type"content="text/html;charset=utf-8"><metaname="viewport"content="width=device-width,initial-scale=1,......
  • 网站频频告警故障排查实录
    故障描述位于某ProxmoxVE超融合集群上的一个网站频频报警,表现的形式是一会儿服务不可用,一会儿又恢复(如下图所示),但同一集群上的其他Web站点未发现异常。可能的原因1)出口带宽占满。2)ProxmoxVE集群故障。3)负载均衡器故障。4)应用服务器故障。5)数据库故障。故障定位1)通过查看IDC出口带......