发布于 2026-01-06 7 阅读
0

使用 Popper 2 实现更智能的工具提示和弹出框 DEV 的全球展示挑战赛,由 Mux 呈现:展示你的项目!

使用 Popper 2 实现更智能的工具提示和弹出框

由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!

四年前,我发布了第一个版本的库,旨在解决一个既简单又复杂的问题:定位弹出框。这些弹出框包括工具提示、弹出框、下拉菜单等等——它们会从文档流中“弹出”,覆盖在现有用户界面之上,并定位在某个参考元素(例如按钮)旁边。

弹出框是日常网络应用的一部分;我们每天使用的所有网站和应用程序都会用到它们,帮助用户界面更好地利用空间。如果所有控件都对用户可见,界面就会变得非常杂乱。但是,这些小部件背后究竟隐藏着什么呢?

工具提示位于 SVG 爆米花框的右侧,并已采取措施防止其超出容器范围,以确保用户始终可见。

构成弹出框最复杂的部分之一是定位逻辑,也就是让弹出框浮动在触发它的元素附近的代码。我们见过多少次弹出框部分定位在页面外、滚动时卡住、页面缩放时无响应、内容被裁剪掉的情况?我能数得过来。现在这种情况可能少了,部分原因可能是像 Popper 这样的库修复了这个问题,但在过去,这种情况要普遍得多。

Popper 专注于解决这个问题。它是一个可靠、轻量级且可扩展的定位引擎库,确保您的工具提示和弹出框处于最佳位置。

采用

图书馆的借阅量非常可观!具体数据如下:

  • 超过 65 万个 GitHub 代码库依赖于它
  • 每周 npm 下载量超过 300 万次
  • CDN 终身访问量超过 10 亿次

npm 下载统计数据。从 2018 年 1 月的每天 5 万次下载量增加到 2019 年 12 月的每天超过 60 万次下载量。

许多大型项目都选择 Popper 作为其工具提示和弹出框的首选库。事实上,即使你之前并不知道 Popper 的存在,但在过去几年里,你很可能已经以开发者或网页用户的身份使用过它。

最流行的 UI 库 Bootstrap、Foundation 和 Material UI 都决定采用它,以帮助用户创建没有用户体验问题的弹出窗口。此外,Drupal 和 Joomla! 等内容管理系统也采用了它,还有微软的 WebClipper 和 Fluent UI、Atlassian 的 AtlasKit、GitLab 等大型公司也纷纷效仿。

问题到底出在哪里?

问题解决了,大家都很高兴;那么接下来还能做什么呢?嗯,也不尽然。

这个API并不友好,自动生成的文档可能让很多人转行,而修复bug更是只有最厉害的英雄才能胜任的艰巨任务。毕竟,这套代码库已经有四年历史了,是由比我年轻四年、经验也更不足的我编写的。

没有软件是永恒的,因此在 2018 年初,也就是 v1.0 发布一年后,我前往 Google 学习如何使用 Git 创建一个干净的分支,几天后,一个新的 Git 分支就准备好承载 Popper 的未来了!

18个月后……

尽管初期开发进展顺利,但后来生活变得忙碌,重写工作也因此搁置了很长时间。毕竟,Popper 1 仍然运行良好,并且用户群体也在不断扩大。

时值2019年中,距离我上次参与Popper新版本的开发已经过去一年多了。v1版本的用户越来越多,但越来越多的bug和API缺陷也开始浮出水面。数百万用户都在使用并依赖这个库,但它几乎每行代码都存在问题。我感到很内疚;我不能让Popper一直这样下去,我必须修复它。

2019年6月,我提交了一个拉取请求寻求帮助,因为我在库的下一个版本中遇到了一个关键部分的问题——检测弹出框相对于给定边界的溢出逻辑。但没有人能够提供帮助。

Popper 2 的前景堪忧,其开发工作已完全停滞。难道 Popper 1 真的会成为网络(包括开发者和用户)唯一可用的工具提示和弹出框定位引擎版本吗?一个漏洞百出、体积庞大的版本?

最终,在提交 pull request 五个月后,我终于想到了一个解决方案。就这样,Popper 2 的开发重新启动了。你可以在这里查看 pull request

@atomiks加入了我们,我们开始合作,最终发布了 Popper 2。我要特别感谢他,因为他帮助开发了许多修改器(功能),使 Popper 2 与 v1 相媲美,但没有 v1 的 bug 😅。

数字发展

你想了解具体数据吗?Popper 2 重启开发两个月以来:

  • 🐞已修复 38 个错误
  • ↩️ 已提交 70 多个 pull request
  • 🎁 20 个新版本发布
  • ✏️ 已推送 600 多个提交
  • ⚡ 更新速度提升 2 倍
  • 🔽 基础库大小缩小 70%

我们做出了改进

那么,究竟发生了什么变化?一切都变了!新的代码库完全重写。它采用更模块化的方式编写,由 Flow 进行类型检查并自动生成 TypeScript 定义,修饰符 API 功能更强大,最重要的是,该库更轻量级、支持 tree shaking 且速度更快!

让我们一起来看看API的两个主要变化。

1. 我们将类替换成了函数:

// Old - bye classes!
const popperInstance = new Popper(reference, popper);

// New - hello closures!
const popperInstance = createPopper(reference, popper);

2. 修饰符是一个对象数组,它具有 aphaserequiresb 属性,这些属性根据修饰符的依赖关系对其进行排序:

const offsetModifier = {
  name: 'offset',
  enabled: true,
  // core phases: read, main, write
  phase: 'main',
  // dependencies
  requires: ['popperOffsets'],
  // core logic
  fn({state}) {}
};

createPopper(reference,  popper, {
  modifiers: [offsetModifier],
});

因此,该order房产不再需要进行任何改动。

感谢 Stack Overflow 用户 Nikhil Aggarwal 提供的修饰符排序算法。当然,他当时并不知道这个算法的用途,但一年半后,我们在这个库中采用了它!您可以在这里查看它的改编版本

让波普节食

Popper 1 虽然功能更多、更可靠,但体积也随之增长。它从一个仅有 3kB 的小库,变成了一个相当大的 7kB!很多用户都问,一个“简单的工具提示库”怎么会这么大。虽然这个问题没有考虑到该库需要支持的海量逻辑和各种极端情况,但这个问题本身仍然值得探讨。

为了减小库的大小,我们采用了两种不同的方法:代码完全重写,并且实现了模块化。

删除旧版破解程序

重写整个库是必要的,这样才能清除多年来引入的大量遗留代码和临时解决方案——尤其是针​​对旧版浏览器(没错,我们说的就是你,IE10)。很多定位逻辑本身就存在缺陷,或者采用了错误的方法。

可扩展的核心

新方法是编写逻辑清晰、无需后续调整的代码。这看似显而易见,但当我们使用浏览器的 DOM API 时,各种各样的问题就会接踵而至。在臃肿的代码库中,最有效的解决方法是添加相应的逻辑来处理这些问题,而不是重写整个代码块。仅此一项就帮助我们将库的大小减少了约 35%,但这还不够!因此,我们采用了模块化设计。

新版库的设计理念是:核心库包含运行 Popper 生命周期所需的逻辑,以及启用各种插件所需的最基本逻辑。在此基础上,我们提供了一系列插件(或称扩展程序),它们为 Popper 添加各种功能,但完全是可选的。这意味着,您现在可以导入 Popper,让它只执行非常基本的定位计算,而无需执行溢出检测、事件监听器、翻转行为、自定义偏移支持等所有必要的逻辑。得益于此,核心库的大小现在仅为 2kB!而包含最常用插件的版本也只有 3kB。

我们修复了文档。

Popper v1 的文档因极其难以阅读和理解而臭名昭著。

一位 YouTube 用户评论道:“这个库的文档是我见过最糟糕的之一,简直令人作呕。” 这条评论获得了 18 个赞。

文档现在已使用 Gatsby 和 MDX 完全重写,希望它能更容易理解。我们还添加了一个教程,其中包含一个完整、可复现的示例,以尽可能帮助初学者。您可以在https://popper.js.org/docs/v2/tutorial/找到它。

对于所有不得不忍受v1版本文档的人,我们深表歉意!🙈

我们欣然接受了对爆米花和游乐园的热爱

我们完全接受了“爆米花”这个名字,并将网站设计成爆米花主题,因为,谁不喜欢爆米花呢?

请访问此网站https://popper.js.org

如果您喜欢并使用 React/Gatsby,欢迎为本网站贡献代码,使其更具游乐园主题和趣味性!GitHub 代码库完全开源,可在此处访问:https://github.com/popperjs/popper-core

总结

这段旅程可谓漫长,但我今天非常激动地向大家发布 Popper 2!欢迎大家留下反馈意见,我们很想听听你们的想法。

文章来源:https://dev.to/fezvrasta/smarter-tooltips-and-popovers-with-popper-2-44bh