如何在 Chrome 扩展内容脚本中正确使用 Floating UI
技术百科
花韻仙語
发布时间:2026-01-28
浏览: 次 本文详解如何绕过 esm 导入限制,在 chrome 扩展 content script 中成功集成 floating ui,实现动态 tooltip 定位,并提供可直接运行的模块化配置与调用方案。
在 Chrome 扩展中使用 Floating UI 构建响应式 tooltip 时,直接引入其 ESM 版本(如 @floating-ui/dom/+esm)会触发 Uncaught SyntaxError: Cannot use import statement outside a module 错误——这是因为 Chrome 内容脚本默认不支持顶层 import 语句,即使 manifest 中声明 "type": "module",若依赖的第三方库自身以裸 import 形式发布(如 Floating UI 的 ESM CDN 链接),仍无法被直接 import 加载。
✅ 正确解法是:改用 UMD(Universal Module Definition)构建版本,通过
✅ 推荐配置步骤
-
在 content_scripts 中按顺序加载 UMD 脚本(非 ESM)
修改 manifest.json,移除 "type": "module"(该字段对 js 数组中的多个脚本不生效),改用显式
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["content.js"],
"css": ["tooltips.css"]
}
]-
在 content.js 开头动态加载 UMD 版本(CDN 推荐)
使用 Floating UI 官方提供的 UMD 构建(v1.x 支持 UMD):
// content.js —— 首先确保 Floating UI 全局可用
if (!window.FloatingUICore || !window.FloatingUIDOM) {
const scriptCore = document.createElement('script');
scriptCore.src = 'https://unpkg.com/@floating-ui/core@1.6.5/dist/floating-ui.core.umd.js';
scriptCore.async = false;
const scriptDOM = document.createElement('script');
scriptDOM.src = 'https://unpkg.com/@floating-ui/dom@1.6.11/dist/floating-ui.dom.umd.js';
scriptDOM.async = false;
document.head.append(scriptCore, scriptDOM);
}
// 等待脚本加载完成后再执行 tooltip 逻辑(推荐 Promise 化或使用 load 事件)
Promise.all([
new Promise(r => scriptCore.onload = r),
new Promise(r => scriptDOM.onload = r)
]).then(() => {
// ✅ 此时 window.FloatingUICore / window.FloatingUIDOM 已就绪
initTooltips();
});-
创建 tooltip 并调用 computePosition
示例:为页面中所有 .tooltip-trigger 元素添加顶部 tooltip:
function initTooltips() {
const triggers = document.querySelectorAll('.tooltip-trigger');
triggers.forEach(trigger => {
const tooltip = document.createElement('div');
tooltip.className = 'floating-tooltip';
tooltip.textContent = 'This is a tooltip!';
const arrow = document.createElement('div');
arrow.className = 'tooltip-arrow';
tooltip.appendChild(arrow);
document.body.appendChild(tooltip);
// 关键:使用挂载到 window 的 UMD 实例
function updatePosition() {
window.FloatingUIDOM.computePosition(trigger, tooltip, {
placement: 'top',
middleware: [
window.FloatingUICore.offset(6),
window.FloatingUIDOM.flip(),
window.FloatingUIDOM.shift({ padding: 5 }),
window.FloatingUIDOM.arrow({ element: arrow }),
],
}).then(({ x, y, middlewareData, placement }) => {
Object.assign(tooltip.style, {
left: `${x}px`,
top: `${y}px`,
});
// 处理箭头定位(需配合 CSS transform)
const { x: arrowX, y: arrowY } = middlewareData.arrow || {};
if (arrowX != null && arrowY != null) {
Object.assign(arrow.style, {
left: `${arrowX}px`,
top: `${arrowY}px`,
});
}
});
}
// 初始定位 + 监听滚动/resize
upd
atePosition();
window.addEventListener('scroll', updatePosition, { passive: true });
window.addEventListener('resize', updatePosition);
});
}⚠️ 注意事项
- ❌ 不要将 floating-esm.js 直接写入 manifest.json 的 js 数组并设 "type": "module" —— Chrome 不允许 content script 同时加载多个模块脚本且跨脚本共享 import 作用域。
- ✅ UMD 版本(.umd.js)是专为浏览器全局环境设计的,无 import/export,天然兼容 content script。
- ? 建议锁定 CDN 版本号(如 @1.6.11),避免因 Floating UI 主版本升级(如 v2+ 移除 UMD)导致扩展失效。
- ? 若需更小体积或定制构建,可自行用 Vite/Webpack 打包 Floating UI 为 IIFE 格式并内联到扩展中。
通过以上方式,你即可在 Chrome 扩展中稳定、高效地利用 Floating UI 实现像素级精准的 tooltip 定位,兼顾性能、兼容性与可维护性。
# 浏览器
# app
# css
# win
# js
# json
# chrome
# red
# 作用域
# cdn
# vite
# webpack
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- Windows怎样关闭桌面弹窗广告_Windows
- PHP cURL GET请求:正确设置请求头与身份
- Python函数接口文档化_自动化说明【指导】
- Win11怎么设置麦克风权限_允许应用访问Win1
- Win11此电脑不在桌面上_Windows 11桌
- Win10系统映像怎么恢复 Win10使用系统映像
- Mac怎么设置鼠标滚动速度_Mac鼠标设置详细参数
- Windows蓝屏BAD_POOL_HEADER故
- Win11如何更改用户账户文件夹名称 Win11修
- 如何使用Golang实现负载均衡_分发请求到多个服
- 如何使用Golang写入二进制文件_Golang
- Mac怎么安装软件_Mac安装dmg与pkg文件的
- Win11无法识别耳机怎么办_解决Win11插耳机
- LINUX怎么查看进程_LINUX ps命令查看运
- Linux怎么修改用户密码_Linux系统pass
- Windows 10怎么录屏_Windows 10
- 微信里的php文件怎么变mp4_微信接收php转m
- Win11怎么关闭开机声音_Win11系统启动提示
- 如何使用正则表达式批量替换重复的“-”模式为固定字
- C++如何编写函数模板?(泛型编程入门)
- Mac的访达(Finder)怎么用_Mac文件管理
- Win11相机打不开提示错误怎么修_相机权限开启与
- 手机php文件怎么变成mp4_安卓苹果打开php转
- Win11如何隐藏桌面图标 Win11一键隐藏/显
- 静态属性修改会影响所有实例吗_php作用域操作符下
- c++ try_emplace用法_c++ map
- 如何使用Golang sort排序切片_Golan
- 如何使用Golang encoding/json解
- Win10系统怎么查看网络连接状态_Windows
- Win11任务栏颜色怎么改_Win11自定义任务栏
- Win11时间怎么同步到原子钟 Win11高精度时
- Win11怎样安装微信开发者工具_Win11安装开
- 如何从 Go 的 map[string]inter
- Linux怎么设置磁盘配额_Linux系统Quot
- c++怎么使用std::tuple存储多元组数据_
- c++ reinterpret_cast怎么用 c
- php怎么连接数据库_MySQL数据库连接的基础代
- Go 中 defer 语句在 goroutine
- Windows怎样拦截WPS弹窗广告_Window
- 如何使用Golang操作指针变量_Golang解引
- c++中如何使用虚函数实现多态_c++多态性实现原
- 如何使用Golang实现路由分组管理_Golang
- Windows笔记本无法进入睡眠模式怎么办?(电源
- Mac怎么给文件夹加密_Mac创建加密磁盘映像教程
- 如何在Golang中实现CI/CD流水线自动化测试
- ACF 教程:如何正确更新嵌套在多层 Group
- WindowsUSB驱动安装异常怎么办_USB驱动
- MAC如何修改默认应用程序_MAC文件后缀关联设置
- Win11怎么设置任务栏图标大小_Windows1
- php错误怎么开启_display_errors与


QQ客服