1. 基本介绍
AutoAnimate 是一个零配置的嵌入式动画实用程序,可为您的 Web 应用程序添加平滑的过渡。您可以将它与 React、Solid、Vue、Svelte 或任何其他 JavaScript 应用程序一起使用。
AutoAnimate 的目标是在不影响开发人员的实施时间或性能预算的情况下大幅改善应用程序的用户体验。
2. 和其他动画库的区别
之前的动画库基本都是开发者要在哪里加上动画,需要我们自己决定或者配置才行,而 AutoAnimate 可以帮助我们自动在整个应用添加合适的动画。
AutoAnimate 使用一行代码即可实现添加合适的动画,我们不需要在编写时列表组件时考虑到 AutoAnimate。
AutoAnimate 可以追溯应用到代码库中的任何标记,包括第 3 方代码 - 只需提供父 DOM 节点,然后让 AutoAnimate 完成剩下的工作。
3. 使用指南
3.1 安装
yarn add @formkit/auto-animate
or
npm install @formkit/auto-animate
3.2 用法
AutoAnimate 本质上是一个 autoAnimate 接受父元素的函数。自动动画将应用于父元素及其直接子元素。当发生以下三个事件之一时,会专门触发动画:
- 一个子级被添加到 DOM 中。
- DOM 中的子级被删除。
- 一个孩子在 DOM 中移动。
3.3 注意事项
使用其他类型的过渡仍然可以。例如,如果您仅使用 CSS 进行样式更改(例如悬停效果),则可以使用标准 CSS 过渡来进行此类样式调整。
- autoAnimate仅当添加、删除或移动父元素(您传递给的元素)的直接子元素时,才会触发动画。
- position: relative如果父元素是静态定位的,它会自动接收。编写样式时请记住这一点。
- 有时,Flexbox 布局不会立即调整其子布局的大小。具有属性的子级flex-grow: 1会在捕捉到其完整宽度之前等待周围的内容。AutoAnimate 在这些情况下效果不佳,但如果您为元素指定更明确的宽度,它应该会像魅力一样工作。
4. 原理介绍
4.1 IntersectionObserver
异步观察目标元素与祖先元素或具有顶级文档的视口的相交的变化。
function observePosition(el: Element) {
const oldObserver = intersections.get(el)
oldObserver?.disconnect()
let rect = coords.get(el)
let invocations = 0
const buffer = 5
if (!rect) {
rect = getCoords(el)
coords.set(el, rect)
}
const { offsetWidth, offsetHeight } = root
const rootMargins = [
rect.top - buffer,
offsetWidth - (rect.left + buffer + rect.width),
offsetHeight - (rect.top + buffer + rect.height),
rect.left - buffer,
]
const rootMargin = rootMargins
.map((px) =>`${-1 * Math.floor(px)}px`)
.join(" ")
const observer = new IntersectionObserver(
() => {
++invocations > 1 && updatePos(el)
},
{
root,
threshold: 1,
rootMargin,
}
)
observer.observe(el)
intersections.set(el, observer)
}
4.2 MutationObserver
监听DOM树的变化,比如增加、删除、移动等DOM操作。
function getElements(mutations: MutationRecord[]): Set<Element> | false {
const observedNodes = mutations.reduce((nodes: Node[], mutation) => {
return [
...nodes,
...Array.from(mutation.addedNodes),
...Array.from(mutation.removedNodes),
]
}, [])
// Short circuit if _only_ comment nodes are observed
const onlyCommentNodesObserved = observedNodes.every(
(node) => node.nodeName === "#comment"
)
if (onlyCommentNodesObserved) returnfalse
return mutations.reduce((elements: Set<Element> | false, mutation) => {
// Short circuit if we find a purposefully deleted node.
if (elements === false) returnfalse
if (mutation.target instanceof Element) {
target(mutation.target)
if (!elements.has(mutation.target)) {
elements.add(mutation.target)
for (let i = 0; i < mutation.target.children.length; i++) {
const child = mutation.target.children.item(i)
if (!child) continue
if (DEL in child) returnfalse
target(mutation.target, child)
elements.add(child)
}
}
if (mutation.removedNodes.length) {
for (let i = 0; i < mutation.removedNodes.length; i++) {
const child = mutation.removedNodes[i]
if (DEL in child) returnfalse
if (child instanceof Element) {
elements.add(child)
target(mutation.target, child)
siblings.set(child, [
mutation.previousSibling,
mutation.nextSibling,
])
}
}
}
}
return elements
}, newSet<Element>())
}
4.3 ResizeObserver
对 Element 的内容或边框或 SVGElement 的边框的尺寸的更改
if (typeofwindow !== "undefined") {
root = document.documentElement
mutations = new MutationObserver(handleMutations)
resize = new ResizeObserver(handleResizes)
resize.observe(root)
}
感兴趣的同学可以关注「FED实验室」微信公众号,了解更多前端前沿资讯。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。