You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Next.js中实现类Nuxt.js/Vue.js网站的流畅动画筛选栏?

在Next.js中实现带流畅动画的动态筛选栏组件

可用工具库推荐

  • Framer Motion:React生态适配Next.js的主流动画库,支持状态驱动动画、布局过渡、内容进入/退出动画,能快速实现筛选栏切换时的流畅过渡效果,API简洁易上手。
  • Radix UI:无样式的基础交互组件库,提供下拉、切换等原生级交互的底层实现,适合自定义筛选栏的交互逻辑,避免第三方UI库的样式束缚。
  • Zustand/React Context:小场景下用React Context管理筛选状态足够,复杂多组件共享状态时,Zustand更轻量高效,可减少不必要的重渲染。

过渡动画实现方案

1. 内容切换的进入/退出动画

用Framer Motion的AnimatePresence组件包裹筛选内容区域,配合motion.div的initial/animate/exit属性,实现切换筛选选项时旧内容淡出、新内容淡入+位移的过渡效果,设置mode="wait"可确保旧动画完成后再启动新动画,避免视觉混乱。

2. 布局自适应动画

给筛选选项按钮添加Framer Motion的layout属性,当选项内容宽度变化或选中状态切换时,元素会自动平滑调整位置和尺寸,无需手动计算过渡参数。

3. 纯CSS过渡(轻量方案)

若不想引入动画库,可通过CSS的transition属性给筛选项的opacity、width、transform等属性添加过渡效果,结合React状态切换控制元素类名,实现基础的平滑过渡。

组件结构建议

拆分粒度

  • FilterBar(主容器):负责管理筛选状态、协调子组件交互、包裹动画逻辑。
  • FilterOption(选项组件):单个筛选按钮,处理点击事件、自身样式和hover/tap微动画,用React.memo包裹避免不必要重渲染。
  • FilterContent(内容区域):根据选中选项渲染对应内容,包裹在动画容器中,确保内容切换时的过渡效果。

状态管理

  • 简单场景:在FilterBar中用useState管理当前选中的筛选键即可。
  • 复杂场景:用Zustand或Context将筛选状态提升,方便其他组件(如列表组件)访问筛选结果。

响应式适配

用Tailwind CSS或原生CSS媒体查询,在小屏幕下将横向筛选栏转为下拉菜单,配合动画组件实现菜单展开/收起的平滑过渡,确保移动端体验一致。

性能优化

  • 用React.memo缓存FilterOption和FilterContent组件,仅在props变化时重渲染。
  • 若筛选内容包含大量数据,可结合React.lazy和Suspense实现懒加载,避免初始加载过慢。

示例代码(基于Framer Motion)

import { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';

const FilterBar = () => {
  const [activeFilter, setActiveFilter] = useState('all');
  const filters = [
    { key: 'all', label: '全部', content: '展示全部内容' },
    { key: 'products', label: '产品', content: '产品分类列表' },
    { key: 'services', label: '服务', content: '企业服务内容' },
  ];

  return (
    <div className="flex flex-col gap-4 p-4 border-b">
      {/* 筛选选项栏 */}
      <div className="flex gap-2">
        {filters.map((filter) => (
          <motion.button
            key={filter.key}
            className={`px-4 py-2 rounded-md ${
              activeFilter === filter.key 
                ? 'bg-blue-600 text-white' 
                : 'bg-gray-100 text-gray-800'
            }`}
            onClick={() => setActiveFilter(filter.key)}
            whileHover={{ scale: 1.03 }}
            whileTap={{ scale: 0.97 }}
            layout
            transition={{ duration: 0.2 }}
          >
            {filter.label}
          </motion.button>
        ))}
      </div>
      {/* 筛选内容区域 */}
      <AnimatePresence mode="wait">
        <motion.div
          key={activeFilter}
          initial={{ opacity: 0, y: 10 }}
          animate={{ opacity: 1, y: 0 }}
          exit={{ opacity: 0, y: -10 }}
          transition={{ duration: 0.3 }}
          className="p-3 bg-gray-50 rounded-md"
        >
          {filters.find(f => f.key === activeFilter)?.content}
        </motion.div>
      </AnimatePresence>
    </div>
  );
};

export default FilterBar;

内容的提问来源于stack exchange,提问作者Mansukh Khandhar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 23:03:24