Gallery算是一个blog中非常基础的需求,看了下gatsby的插件库,貌似是有一个gatsby-theme-gallery
。但是这个插件引入了theme概念,对我来说无用,而且我需求的并不是要一个site级别的gallery,而是一个post级别的gallery,所以不合用。还是自己做一个得了。
主要参考了:Creating a Custom Photo Gallery using Gatsby.js and CSS Grid。此外,我的gatsby使用的是alxshelepenok/gatsby-starter-lumen这个starter,技术上倒是无所谓用的是哪个starter,但文件夹结构是因应着这个starter的结构,所以姑且这里提下。
另外还有一个插件:browniebroke/gatsby-image-gallery,不过看了下用起来也蛮麻烦的,再说了。
关于gatsby的一些技术点,及如何制作自制插件之类的,会在另一篇博文里展开,这里就不提了。
这里按当前这篇post进行举例,来说明下大致上的post相关文件及gallery相关图片文件的存放位置。
root /
| content /
| posts /
| 2021 /
| 09 /
| gallery-example.md # 这是博文本身
| static /
| media /
| posts /
| 2021 /
| 09 /
| gallery-example /
| gallery / *.jpeg # 将会展示在gallery内的图片
| *.jpeg # 其他会在post内使用的图片
gallery-example
/content/posts/YYYY/MM/${slug}.md
/static/media/posts/YYYY/MM/${slug}/*.jpeg
gallery
文件夹,里面的图片会被gallery插件使用,展示在post的EOF
之后:/static/media/posts/YYYY/MM/${slug}/gallery/*.jpeg
大致上就这样,主要就是在media的post专属文件夹里新添加了一个gallery文件夹,里面的图片都会作为post的专属gallery展示在EOF之后。
这里展示一张不会在gallery里展出的图片,因为它是存放在post的media文件夹内,但在gallery文件夹之外的图片:/static/media/posts/2021/09/gallery-example/non-gallery.jpeg
。
代码改动主要是下面几个:
gatsby-config.js # 添加gatsby-plugin-image插件,该图片展示插件在lumen这个starter中不存在
gatsby/create-page.js # 在post-template.js使用的context中添加gallery参数,该值为static的media文件夹下post对应的gallery文件夹
src/types/gallery.js # 描述从graphql内查询出来的allFile数据结构,这会作为gallery参数传给Post
src/templates/post-template.js # 在该template的page query中根据create-page.js给的gallery参数,查询对应路径的图片文件信息allFile;PostTemplate的传入参数data里会有一个新的节点allFile,把它作为gallery参数传给Post
src/components/Post/Gallery/Gallery.js # 组件实现js
src/components/Post/Gallery/Gallery.module.scss # 组件style
src/components/Post/Gallery/index.js # 组件index,直接引入Gallery.js
src/components/Post/Post.js # 判断Post新的传入参数gallery,如果里面有图片,则在Content后面追加Gallery组件
createPage({
path: edge.node.fields.slug,
component: path.resolve('./src/templates/post-template.js'),
context: { slug: edge.node.fields.slug, gallery: `media${edge.node.fields.slug}/gallery` }
});
query PostBySlug($slug: String!, $gallery: String!) {
markdownRemark(fields: { slug: { eq: $slug } }) {
###
others
###
}
allFile(filter: { relativeDirectory: { eq: $gallery } }) {
totalCount
nodes {
childrenImageSharp {
gatsbyImageData
}
}
}
}
return (
<Layout title={`${postTitle} - ${siteTitle}`} description={metaDescription} socialImage={socialImageUrl} >
<Post post={data.markdownRemark} gallery={data.allFile} />
</Layout>
);
// @flow strict
import React from 'react';
import { GatsbyImage } from 'gatsby-plugin-image';
import styles from './Gallery.module.scss';
import type { GalleryData } from '../../../types/gallery';
type Props = {
gallery: GalleryData
};
const Gallery = ({ gallery }: Props) => {
const images = [];
// eslint-disable-next-line no-restricted-syntax
for (const [index, node] of gallery.nodes.entries()) {
const imgKey = `gallery-img-${index}`;
const sharp = node.childrenImageSharp[0];
if (sharp) {
const image = sharp?.gatsbyImageData;
if (image) {
images.push(
<GatsbyImage key={imgKey} alt={imgKey} image={image} />
);
}
}
}
if (images.length > 0) {
return (
<div className={styles['gallery']}>
{images}
</div>
);
}
return null;
};
export default Gallery;
<div className={styles['post__content']}>
<Content body={html} title={title} />
{galleryNode}
</div>
EOF