组件
进入视口 In View
当内容进入视口时播放可配置的入场动画。
基础示例
Loading…
pnpm dlx wui@latest add @wui/in-view"use client"
import * as React from "react"
import {
motion,
useInView as useMotionInView,
useReducedMotion,
type HTMLMotionProps,
type Transition,
type UseInViewOptions,
type Variants,
} from "motion/react"
const defaultVariants: Variants = {
hidden: { opacity: 0, y: 16 },
visible: { opacity: 1, y: 0 },
}
export interface InViewProps extends Omit<
HTMLMotionProps<"div">,
"children" | "variants"
> {
/** Content animated when it enters the viewport. */
children: React.ReactNode
/** Hidden and visible animation states. */
variants?: Variants
/** Motion transition used between states. */
transition?: Transition
/** Intersection observer options such as `margin` and `amount`. */
viewOptions?: UseInViewOptions
/** Only play the entrance animation once. @default true */
once?: boolean
/** HTML element rendered by the component. @default "div" */
as?: React.ElementType
}
/** Animates content when it enters the viewport. */
function InView({
children,
variants = defaultVariants,
transition = { duration: 0.45, ease: "easeOut" },
viewOptions,
once = true,
as = "div",
...props
}: InViewProps) {
const ref = React.useRef<HTMLElement>(null)
const reduceMotion = useReducedMotion()
const isInView = useMotionInView(ref, { ...viewOptions, once })
const MotionComponent = React.useMemo(() => motion.create(as), [as])
return (
<MotionComponent
ref={ref}
data-slot="in-view"
initial={reduceMotion ? false : "hidden"}
animate={reduceMotion || isInView ? "visible" : "hidden"}
variants={variants}
transition={reduceMotion ? { duration: 0 } : transition}
{...props}
>
{children}
</MotionComponent>
)
}
export { InView }
组件作用
InView 适合延后展示长页面中的说明、数据段或媒体内容。它使用浏览器交叉观察能力判断可见性,默认只播放一次,并在减少动态效果偏好下直接显示最终状态。
组件属性
| Prop | Type | Default | Description |
|---|---|---|---|
| children * | ReactNode | — | Content animated when it enters the viewport. |
| variants | Variants | { hidden: { opacity: 0, y: 16 }, visible: { opacity: 1, y: 0 }, } | Hidden and visible animation states. |
| transition | Transition | { duration: 0.45, ease: "easeOut" } | Motion transition used between states. |
| viewOptions | UseInViewOptions | — | Intersection observer options such as `margin` and `amount`. |
| once | boolean | true | Only play the entrance animation once. |
| as | ElementType<any, keyof IntrinsicElements> | div | HTML element rendered by the component. |
事件
组件透传底层元素的原生事件。需要获知可见状态时,可通过自定义 variants 的 Motion 回调处理;viewOptions 支持 margin 与 amount 等观察参数。
扩展使用
通过 as="section" 调整语义元素;设置 once={false} 可在每次进入和离开视口时重播。对于很长的列表,应只为关键内容添加入场效果。