Skip to content

w0fv1/FloatyJS

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FloatyJS

FloatyJS 现在是一个基于原生 JavaScript 的主从式浮窗工具。

  • floaty-main.js 用在宿主页面,负责悬浮按钮、iframe 浮窗、页面上下文采集、截图、与 iframe 通信
  • floaty-slave.js 用在 iframe 页面,负责向宿主页面请求上下文,并暴露易于调用的全局对象

这套结构更适合和 AI 工具配合使用,因为 iframe 侧可以主动获取:

  • 当前页面纯文本
  • 当前焦点元素及其祖先链
  • 当前鼠标位置对应元素及其祖先链
  • 当前页面截图
  • 面向 AI 的组合快照

文件说明

  • floaty-main.js 宿主页面入口,暴露 window.FloatyMain
  • floaty-slave.js iframe 页面入口,暴露 window.FloatySlave
  • floaty.js 兼容入口,会转发到 floaty-main.js
  • index.html 完整宿主页演示台,同时保留 README.md 的在线渲染
  • iframe.html 完整从页演示台,用于演示 FloatySlave 的各种能力
  • serve.py 本地静态服务器脚本,启动后可直接打开 demo

快速开始

1. 宿主页面接入

<script
  type="module"
  src="./floaty-main.js"
  data-theme-color="#111827"
  data-button-text="AI"
  data-tooltip-text="点击打开 AI 浮窗"
  data-window-width="1000px"
  data-window-height="800px"
  data-window-title="FloatyJS Main"
  data-target-link="./iframe.html"
  data-position="bottom-right"
  data-dark="false"
  data-close-on-outside-click="true"
  data-page-info="这是一个电商商品详情页,当前用户已登录,默认展示标准版套餐。"
  defer
></script>

2. iframe 页面接入

<script type="module" src="./floaty-slave.js"></script>

接入后,iframe 页面里会得到一个全局对象:

window.FloatySlave

宿主侧配置

  • data-theme-color 悬浮按钮颜色,默认 #111827
  • data-button-text 按钮文本,默认 💬
  • data-tooltip-text 按钮提示文本
  • data-window-width 浮窗宽度
  • data-window-height 浮窗高度
  • data-window-title 浮窗标题
  • data-window-theme-color 浮窗背景色
  • data-target-link iframe 目标地址
  • data-position 支持 bottom-rightbottom-lefttop-righttop-left
  • data-dark 是否启用暗色浮窗
  • data-close-on-outside-click 点击浮窗外部时是否关闭,默认 true
  • data-page-info 预先提供给从页的页面补充信息或描述,会在 getPageText() / page:text 中返回
  • data-screenshot-library-url 截图库地址,默认使用 html2canvas

宿主侧对象

宿主页面加载后会暴露:

window.FloatyMain
window.floaty

可用方法:

window.FloatyMain.open();
window.FloatyMain.close();
window.FloatyMain.toggle();
window.FloatyMain.setPageInfo("这是一个订单确认页,价格单位为人民币。");
window.FloatyMain.getPageInfo();
window.FloatyMain.syncPageText();
window.FloatyMain.sendEvent("custom:event", { hello: "world" });
window.FloatyMain.getFocusContext({ depth: 5 });
window.FloatyMain.getPointerContext({ depth: 5 });
window.FloatyMain.getInteractionContext({ depth: 5 });
window.FloatyMain.captureScreenshot({ includePointer: true, fullPage: false });
window.FloatyMain.getAISnapshot({ depth: 5, includeScreenshot: true });
window.FloatyMain.getState();
window.FloatyMain.destroy();

从页对象

iframe 页面加载后会暴露:

window.FloatySlave

可用方法:

await window.FloatySlave.getPageText();
await window.FloatySlave.getFocusContext({ depth: 5 });
await window.FloatySlave.getPointerContext({ depth: 5 });
await window.FloatySlave.getInteractionContext({ depth: 5 });
await window.FloatySlave.captureScreenshot({
  includePointer: true,
  fullPage: false,
});
await window.FloatySlave.getAISnapshot({
  depth: 5,
  includeScreenshot: true,
  screenshot: { includePointer: true },
});

getPageText() 返回示例:

{
  "text": "页面纯文本...",
  "page": {
    "title": "Demo",
    "url": "http://localhost:8000/index.html"
  },
  "pageInfo": "这是一个商品详情页,用户当前正在比较不同套餐。"
}

从页也支持监听宿主发来的事件:

const off = window.FloatySlave.on("page:text", (payload) => {
  console.log(payload.text);
  console.log(payload.pageInfo);
});

焦点元素与鼠标元素上下文

默认会向上采集 5 层 DOM 祖先链,可通过 depth 修改:

const focus = await window.FloatySlave.getFocusContext({ depth: 8 });
const pointer = await window.FloatySlave.getPointerContext({ depth: 8 });

返回结构示例:

{
  "page": {
    "title": "Demo",
    "url": "http://localhost:8000/index.html",
    "origin": "http://localhost:8000",
    "lang": "zh",
    "viewport": {
      "width": 1280,
      "height": 720,
      "scrollX": 0,
      "scrollY": 0
    }
  },
  "focus": {
    "depth": 5,
    "chain": [
      {
        "level": 0,
        "tagName": "span",
        "selector": "span.demo",
        "id": null,
        "className": "demo",
        "text": "当前元素文本",
        "attributes": {},
        "rect": {
          "top": 120,
          "left": 240,
          "width": 80,
          "height": 20
        },
        "html": "<span class=\"demo\">当前元素文本</span>"
      }
    ]
  }
}

截图能力

从页可直接请求宿主页面截图:

const screenshot = await window.FloatySlave.captureScreenshot({
  includePointer: true,
  fullPage: false,
  format: "image/png",
  scale: 1
});

返回结构示例:

{
  "format": "image/png",
  "fullPage": false,
  "includePointer": true,
  "cursorIncluded": true,
  "note": "Pointer is rendered as a simulated overlay based on the latest tracked mouse position.",
  "width": 1280,
  "height": 720,
  "dataUrl": "data:image/png;base64,...",
  "page": {},
  "pointer": {
    "clientX": 320,
    "clientY": 180,
    "pageX": 320,
    "pageY": 180
  }
}

说明:

  • 浏览器没有稳定的原生 API 直接把系统鼠标指针一起截进 DOM 截图
  • includePointer: true 时,FloatyJS 会根据最近一次鼠标位置,在截图上叠加一个模拟指针

AI Snapshot

如果你希望给 AI 一次性提供页面文本、焦点元素、鼠标元素,甚至截图,可以直接使用:

const snapshot = await window.FloatySlave.getAISnapshot({
  depth: 5,
  includeScreenshot: true,
  screenshot: {
    includePointer: true,
    fullPage: false
  }
});

这通常是最适合 AI 调用的一种方式。若主页面提前设置了 pageInfo,它也会一并出现在返回结果里。

消息格式

FloatyJS 主从之间通过 postMessage 传输统一 envelope:

{
  "namespace": "floatyjs",
  "version": "2.0.0",
  "source": "floaty-main",
  "target": "floaty-slave",
  "type": "request",
  "action": "page:getFocusContext",
  "requestId": "1711111111111-abcd1234",
  "success": true,
  "payload": {
    "depth": 5
  },
  "error": null,
  "sentAt": "2026-03-22T12:34:56.000Z"
}

字段说明:

  • namespace 固定为 floatyjs
  • version 当前协议版本
  • source floaty-mainfloaty-slave
  • target floaty-mainfloaty-slave
  • type eventrequestresponse
  • action 具体动作名,如 readypage:getScreenshot
  • requestId 请求响应关联 ID
  • payload 业务数据
  • success 仅响应时有意义
  • error 错误信息

本地预览

运行:

python serve.py

然后打开:

http://127.0.0.1:8000/index.html

默认的 demo 结构:

  • index.html 展示宿主页控制台、交互沙箱、截图预览和 README 文档
  • iframe.html 展示从页控制台、事件日志、截图预览和 AI Snapshot 演示

备注

  • 现在已经不再依赖 Lit
  • 现在推荐直接使用 floaty-main.js / floaty-slave.js
  • floaty.js 只是兼容入口

About

一个轻量级且可定制的悬浮按钮和窗口组件.

Resources

Stars

Watchers

Forks

Contributors