Next.js 的砌体布局

Masonry layout with Next.js

我正在开发一个多页面网站,前端使用 Next.js,后端使用 Strapi。在博客页面上,数据是从数据库中动态获取的。我正在尝试使用 Masonry 在自适应布局中显示此数据。

我遇到的问题是,在第一次加载时,页面在单个垂直列中显示每个网格项目。重新加载时,Masonry 布局会生效,但有一些重叠的项目。在第二次重新加载时,所有内容都会正确显示,甚至可以响应。但是,如果我离开该页面并返回,它又回到了原点。

这是博客页面的代码:

import React from 'react';
import Layout from '../components/StaticLayout';
import Link from 'next/link';
import fetch from 'isomorphic-unfetch';
import '../../static/styles.min.css';

let Masonry = '';

export default class Blog extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      appIsMounted: false
    }
  }

  static async getInitialProps() {
    const res = await fetch('http://localhost:1337/blogposts');
    const data = await res.json();

    return {
      posts: data
    };
  }

  async componentDidMount() {
    let masonry = await import('masonry-layout');
    this.setState({
      appIsMounted: true
    })
  }

  render() {
    return (
      <Layout>
        <h1 className="blogHeader">Blog</h1>
        {this.state.appIsMounted ? (
          <div className="grid js-masonry" data-masonry-options='{ "itemSelector": ".grid-item", "columnWidth": 400 }'>
            {this.props.posts.map(
              post => (
                <div key={post.id} className="grid-item">
                  <Link href="/p/[id]" as={`/p/${post.id}`}>
                    <img src={`http://localhost:1337${post.Image.url}`} alt={post.Image.name} className="postImage" />
                  </Link>
                  <div className="text">
                    <Link href="/p/[id]" as={`/p/${post.id}`}>
                      <a className="postLink">{post.Title}</a>
                    </Link>
                    <p className="blurb">{post.Content.substring(0, 300) + '...'}</p>
                    <Link href="/p/[id]" as={`/p/${post.id}`}>
                      <button className="viewPost">Read More!</button>
                    </Link>
                  </div>
                </div>
              )
            )}
          </div>
        ) : null}
      </Layout>
    )
  }
}

请注意,StaticLayout 脚本仅确保页眉位于每个页面的顶部。

编辑

所以我已经解决了问题的重叠部分。我没有在 html 中初始化 Masonry,而是在“./static”中添加了一个 js 文件。在我的博客页面上,我添加了以下内容:

import Head from 'next/head'

...

return(
  <Head>
    <script type="text/javascript" src="/static/runMasonry.js"></script>
  </Head>
  ...
)

runMasonry.js 文件如下所示:

window.onload = function () {
  var elem = document.querySelector('.grid');
  var msnry = new Masonry(elem, {
    // options
    itemSelector: '.grid-item',
    columnWidth: 160,
    gutter: 20
  });
}

但是当我第一次到达页面或离开并返回时,元素仍然显示在一列中并需要重新加载。

想出了一个不理想的修复方法,但它有效。

runMasonry.js 文件中添加了以下代码:

window.addEventListener("DOMSubtreeModified", function () {
    var elem = document.querySelector('.grid');
    if (elem) {
        var msnry = new Masonry(elem, {
            // options
            itemSelector: '.grid-item',
            columnWidth: 160,
            gutter: 20
        });
    }
});

因此它会检测何时加载新页面内容,如果它找到我的 .grid 元素,则重新运行 masonry。

保持开放状态,以防有人能提供更好的长期解决方案。