关于浮动元素,你还在自己计算位置吗?来看看 Floating UI 吧!

简介: 关于浮动元素,你还在自己计算位置吗?来看看 Floating UI 吧!

什么是浮动元素?就是在页面布局之外浮动,而不会破坏页面布局的元素。

浮动元素在实际项目中有广泛的使用。比如工具提示、弹出框、下拉菜单等。

拿掘金举例。

比如这样:

image.png

这样:

image.png

还有这样:

image.png

它的原理并不复杂,通过相对定位和绝对定位计算 left 和 top 两个值就可以。

但是实际上我们很少去手动计算位置,因为太麻烦了。

在过去,最受大家欢迎的是 Popper 这个库,而且它是一个非常老牌的库,在 2006 年就开源了,几乎是这个领域内做的最大的。

但是现在有了一个更新、更全能的 Floating UI!

Floating UI 同样是 Popper 团队开发的,是在 Popper v2 版本之上的演变。

Floating UI 当然不仅仅是 Popper 的替代品,而是多了很多新的功能。


优势

跨平台兼容


浮动元素不只是 HTML 独有的需求,在移动端、Canvas、WebGL 等其他通过 JavaScript 编写的环境中,都有这个需求。所以 Floating UI 可以在原生 JS、React、React Native 等环境中使用。


体积


Floating UI 的体积仅有 600 b,而且它支持摇树。相比之下 Popper 3kb 的体积,并且不可摇树,显得非常臃肿了。


快速入门

安装


Floating UI 有好几个包,分别对应不同的平台。

下面是 Web 平台的包。


npm i @floating-ui/dom

如果想省事,还可以使用 ESM 格式通过 CDN 来加载 Floating UI。


<script type="module">
  import * as FloatingUIDOM from 'https://cdn.skypack.dev/@floating-ui/dom';
</script>

computePosition


computePosition 是 Floating UI 的核心 API,它可以通过计算浮动元素的坐标将其定位在参考元素旁边。

我们利用这个 API 制作一个工具提示来尝试一下。

这是 html 部分。


<button id="button" aria-describedby="tooltip">我是一个按钮</button>
<div id="tooltip" role="tooltip">我是一个悬浮的工具提示</div>

包含了一个按钮一个 div,我们想让 div 浮动到按钮的正下方。

再来添加一些样式。


#tooltip {
  color: #fff;
  background: #363636;
  font-size: 1.2rem;
  padding: 10px 15px;
  border-radius: 8px;
  position: absolute;
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1), 0 3px 3px rgba(0, 0, 0, 0.05);
}
button {
  border-radius: 8px;
  border: none;
  outline: none;
  font-size: 1.2rem;
  cursor: pointer;
  padding: 10px 15px;
  color: #fff;
  background: rgb(48, 19, 129);
}

最后实现我们的功能。


import { computePosition } from "https://cdn.skypack.dev/@floating-ui/dom";
const button = document.querySelector("#button");
const tooltip = document.querySelector("#tooltip");
computePosition(button, tooltip).then(({ x, y }) => {
  Object.assign(tooltip.style, {
    left: `${x}px`,
    top: `${y}px`,
  });
});

我们首先获取到两个元素,button 是参考元素,tooltip 是浮动元素。

然后通过异步计算,得到 x 和 y 的坐标,设置到浮动元素上,完成定位。

我们还可以设置元素不同的位置,这通过 computePosition 的第三个参数来完成。


computePosition(button, tooltip , { placement: 'top-start' })

placement 可以指定浮动元素应该靠近参考元素的哪一侧。

image.png

一共有 12 个选项。

  • left-start
  • left
  • left-end
  • top-start
  • top
  • top-end
  • right-start
  • right
  • right-end
  • bottom-start
  • bottom
  • bottom-end

默认值是 bottom。


中间件


Floating UI 还提供了中间件的概念,就是在调用 computePosition 之后,then 之前运行的一段代码,可以改变浮动元素的定位和行为。

中间件是实现除了基本定位功能之外的其他功能统一的方式。

Floating UI 提供了下面几个中间件:

  • offset:修改参考元素和浮动元素之间的间距
  • shift:移动浮动元素,让它保持始终可见。它还会处理元素溢出到窗口之外的情况。
  • flip:帮我们修改坐标,如果我们设置浮动元素在顶部,但是距离顶部太近,会放置到底部。
  • size:调整浮动元素的大小。
  • autoPlacement:通过选择可用空间最多的位置来自动确定浮动元素的位置。
  • inline:改进跨多行的内联元素的定位,比如 a 标签。

使用中间件:


computePosition(button, tooltip, {
  placement: "top",
  middleware: [offset(4), flip(), shift({padding: 5})],
}).then(({ x, y }) => {
  // ...
});

中间件的使用也是有顺序的,比如 offset 应该始终处于数组的第一个位置。


交互


到现在为止,我们也只是解决了定位的问题。交互的问题还没有处理。

现在工具提示是一直显示的,通常情况下,它应该默认是隐藏状态,当我们通过某种交互事件后,它才会显示。比如点击、鼠标悬停等。

为了实现交互功能,我们需要封装代码。


function setUpTooltip() {
  computePosition(button, tooltip, {
    placement: "top",
    middleware: [offset(4), flip(), shift({ padding: 5 })],
  }).then(({ x, y }) => {
    Object.assign(tooltip.style, {
      left: `${x}px`,
      top: `${y}px`,
    });
  });
}
function showTooltip() {
  tooltip.style.display = "block";
  setUpTooltip();
}
function hideTooltip() {
  tooltip.style.display = "none";
}

现在只需要调用 showTooltip 就可以控制元素显示,调用 hideTooltip 就可以控制元素隐藏。

我们把这两个函数绑定到元素的鼠标移入移出事件上。


[
  ["mouseenter", showTooltip],
  ["mouseleave", hideTooltip],
].forEach(([event, listener]) => {
  button.addEventListener(event, listener);
});

现在功能就全部完成了。


在 React 中使用 Floating UI


在 React 中使用 Floating UI 非常友好,它提供了对应的包,我们只需要换成这个包就可以了。

bash

复制代码

npm install @floating-ui/react-dom

要实现上面演示的原生案例,对应的 React 代码如下:


import { useFloating, shift, offset, flip, useInteractions, useHover } from "@floating-ui/react-dom";
export default function App() {
  const [open, setOpen] = useState(true);
  const { x, y, reference, floating, strategy, context } = useFloating({
    placement: "right",
    middleware: [offset(4), flip(), shift({ padding: 5 })],
    open,
    onOpenChange: setOpen,
  });
  const { getReferenceProps, getFloatingProps } = useInteractions([
    useHover(context),
  ]);
  return (
    <>
      <button ref={reference} {...getReferenceProps()}>Button</button>
      { open && <div
        id="tooltip"
        ref={floating}
        style={{ top: y, left: x }}
        {...getFloatingProps()}
      >
        Tooltip
      </div>
      }
    </>
  );
}

可以看到,Floating UI 在 React 中具有了更多的功能,比如提供了 useInteractions Hook 帮助我们处理交互的问题。


总结


通过在几个项目中使用 Floating UI,我总结出的优点有以下几个:

  • API 友好,几乎不需要多做其他事情。
  • 文档和示例完善,可以去官网上复制代码。
  • 体积小,支持摇树,性能更好。
  • 跨环境,有 JavaScript 的地方就可以使用。
  • 跨框架,原生、React、Vue 等都可以使用。

关于 Floating UI 的介绍就到这里,快去试试吧。



相关文章
|
5月前
|
前端开发 算法 Java
【CSS】前端三大件之一,如何学好?从基本用法开始吧!(二):CSS伪类:UI伪类、结构化伪类;通过伪类获得子元素的第n个元素;创建一个伪元素展示在页面中;获得最后一个元素;处理聚焦元素的样式
伪类:伪类这个叫法源自于它们跟类相似,但实际上并没有类会附加到标记中的标签上。 伪类分为两种(以及新增的伪类选择器): UI伪类:会在HTML元素处于某种状态时(例如:鼠标指针位于连接上),为该元素应用CSS样式。 :hover 结构化伪类:会在标记中存在某种结构上的关系时 例如: 某元素是一组元素中的第一个或最后一个,为该元素应用CSS样式。 :not和:target(CSS3新增的两个特殊的伪类选择器)
539 2
|
10月前
|
开发者 容器
【HarmonyOS Next之旅】ArkTS语法(二) -> 动态构建UI元素
当开发者创建自定义组件,并想对该组件添加特定功能时(例如在自定义组件中添加一个点击跳转操作)。为解决此问题,引入了@BuilderParam装饰器,此装饰器修饰的属性值可为@Builder装饰的函数,开发者可在初始化自定义组件时对此属性进行赋值,为自定义组件增加特定的功能。@BuilderParam装饰器用于修饰自定义组件内函数类型的属性(例如:@BuilderParam noParam: () => void),并且在初始化自定义组件时被@BuilderParam修饰的属性必须赋值。
284 11
|
9月前
|
JavaScript 测试技术 Python
UI自动化测试中的元素等待机制解析
在UI自动化测试中,元素定位失败常因页面存在iframe或缺乏合理等待机制。本文解析三种等待策略及其应用场景:显式等待可精确控制单个元素等待条件,支持自定义轮询;隐式等待全局生效,适合简单页面加载;强制等待仅用于临时调试,正式脚本慎用。通过对比三者执行精度、资源消耗及适用场景,帮助选择最优策略,提升测试效率与稳定性。
|
开发工具 Android开发 开发者
Android `.9.png` 图像是用于UI的可拉伸格式,保持元素清晰度和比例
【6月更文挑战第26天】Android `.9.png` 图像是用于UI的可拉伸格式,保持元素清晰度和比例。通过边上的黑线定义拉伸区域,右下角黑点标识内容区域,适应文本或组件大小变化。常用于按钮、背景等,确保跨屏幕尺寸显示质量。Android SDK 提供`draw9patch.bat`工具来创建和编辑。**
445 6
|
前端开发 开发工具 git
Element UI 【表格合计】el-table 实战范例 -- 添加单位,自定义计算逻辑
Element UI 【表格合计】el-table 实战范例 -- 添加单位,自定义计算逻辑
1101 0
Element UI 表单【详解】-- 表单校验,表单元素排列在一行,常用表单元素等
Element UI 表单【详解】-- 表单校验,表单元素排列在一行,常用表单元素等
797 0
element-ui框架的el-dialog弹出框被遮罩层挡住了/el-drawer....会生成v-model元素的组件被遮罩层挡住
element-ui框架的el-dialog弹出框被遮罩层挡住了/el-drawer....会生成v-model元素的组件被遮罩层挡住
1060 1
|
开发工具 Android开发 iOS开发
如何使用 Draggable 和 DragTarget 在 Flutter 中创建拖放 UI 元素?
如何使用 Draggable 和 DragTarget 在 Flutter 中创建拖放 UI 元素?
842 0
|
数据安全/隐私保护 索引
element-ui库的表单元素的总结
element-ui库的表单元素的总结
531 0

热门文章

最新文章