如何在Next.js项目中实现isotope-layout布局?
Next.js 中集成 Isotope-Layout 的解决方案
你的报错本质是Next.js 服务端渲染阶段不存在 window 对象,而 Isotope-Layout 依赖浏览器环境的 window,直接导入会触发这个错误。以下是几种可行的解决方法:
方法一:动态导入组件并禁用 SSR
使用 Next.js 内置的 next/dynamic 工具,将 Isotope 相关组件设置为仅客户端渲染:
1. 封装 Isotope 组件
创建 components/IsotopeGrid.tsx:
import { useEffect, useRef, useState } from 'react'; import Isotope from 'isotope-layout'; interface GridItem { id: string; category: string; content: string; } const IsotopeGrid = ({ items }: { items: GridItem[] }) => { const gridRef = useRef<HTMLDivElement>(null); const [isotopeInstance, setIsotopeInstance] = useState<Isotope | null>(null); // 初始化 Isotope useEffect(() => { if (!gridRef.current) return; const isotope = new Isotope(gridRef.current, { itemSelector: '.grid-item', layoutMode: 'masonry', gutter: 10 // 可根据需求调整 }); setIsotopeInstance(isotope); // 组件卸载时销毁实例 return () => isotope.destroy(); }, []); // 过滤逻辑 const handleFilter = (category: string) => { isotopeInstance?.arrange({ filter: category === 'all' ? '*' : `.${category}` }); }; return ( <> <div className="filter-buttons"> <button onClick={() => handleFilter('all')}>全部</button> <button onClick={() => handleFilter('category1')}>分类1</button> <button onClick={() => handleFilter('category2')}>分类2</button> </div> <div ref={gridRef} className="grid-container"> {items.map(item => ( <div key={item.id} className={`grid-item ${item.category}`}> {item.content} </div> ))} </div> </> ); }; export default IsotopeGrid;
2. 在页面中动态导入组件
在页面文件(如 pages/isotope.tsx)中使用动态导入:
import dynamic from 'next/dynamic'; // 禁用 SSR,仅在客户端渲染 const IsotopeGrid = dynamic(() => import('../components/IsotopeGrid'), { ssr: false, loading: () => <div>加载中...</div> }); const IsotopePage = () => { const gridItems = [ { id: '1', category: 'category1', content: '项目卡片1' }, { id: '2', category: 'category2', content: '项目卡片2' }, { id: '3', category: 'category1', content: '项目卡片3' }, { id: '4', category: 'category2', content: '项目卡片4' } ]; return <IsotopeGrid items={gridItems} />; }; export default IsotopePage;
方法二:在 useEffect 中动态导入 Isotope
如果不想整个组件禁用 SSR,可以在客户端生命周期钩子中动态加载 Isotope:
import { useEffect, useRef } from 'react'; interface GridItem { id: string; category: string; content: string; } const IsotopeGrid = ({ items }: { items: GridItem[] }) => { const gridRef = useRef<HTMLDivElement>(null); useEffect(() => { const initIsotope = async () => { // 仅在客户端环境导入 Isotope const Isotope = (await import('isotope-layout')).default; if (gridRef.current) { const isotope = new Isotope(gridRef.current, { itemSelector: '.grid-item', layoutMode: 'fitRows' }); return () => isotope.destroy(); } }; initIsotope(); }, [items]); return ( <div ref={gridRef} className="grid-container"> {items.map(item => ( <div key={item.id} className={`grid-item ${item.category}`}> {item.content} </div> ))} </div> ); }; export default IsotopeGrid;
额外注意事项
- 确保添加基础样式,比如给
.grid-container设置宽度,.grid-item设置固定宽度,否则 Isotope 布局可能异常。 - 如果使用 TypeScript,需要安装类型声明:
npm install @types/isotope-layout --save-dev
内容的提问来源于stack exchange,提问作者David H
相关产品推荐
相关产品推荐

