用 Gatsby 搭建静态博客 2

Posted by Sir0xb on 2019-02-01 10:28:00 +0800

上一篇做了导航菜单、弄出了博文列表、博文预览及翻页器。

基本的功能弄的差不多了,不过还需要用这些基本功能再完善一下博客。

首页也需要改改、返回顶部的按钮、还有本人比较喜欢的滚动条进度条、统计、Google被搜索等等。


6. 改版首页

博客首页的传统实现方式是显示部分博文,下方再加个 Read More 的按钮。

只有一种首页是不是太单调了,在特殊节日我想搞个特效页面什么的展示在首页。 所以,我弄了个配置,如果是普通日子,就默认用传统的有分页,博文部分显示的首页。 如果是特殊节日,根据开发的特效页面不同,也能很快的进行切换。

首先,我们把原先的入口文件 src/pages/index.js 更名或删除。

并创建模板文件 src/templates/home.js

import React from 'react'
 
import Layout from '../components/layout'
import HomePage from '../components/Home'
import SEO from '../components/seo'
 
const Template = ({ pageContext }) => (
<Layout>
<SEO title="Boliball" />
<HomePage type="normal" pageContext={pageContext} />
</Layout>
)
 
export default Template

通过这种方式,我们可以把给入模板文件的页面上下文转移到 src/components/Home/index.jsx 里。

我们再改下高级渲染方式 gatsby-node.js,把组织数据部分弄一弄。

...
// 生成首页
const HomeTemplate = path.resolve('./src/templates/home.js')
createPaginatedPages({
edges        : result.data.allMarkdownRemark.edges,
createPage   : createPage,
pageTemplate : HomeTemplate,
pageLength   : 5,
pathPrefix   : ''
})
...

上下文数据有了,模板也有了,弄一弄首页 Component 吧。

先弄一个组件路由。

import React from 'react'
import PropTypes from 'prop-types'
 
import NormalHomePage from './normal'
import HolidayHomePage from './holiday'
 
const HomeComponentMapping = {
normal  : NormalHomePage,
holiday : HolidayHomePage
}
 
const HomePage = ({ type, pageContext }) => {
const TheHomePage = HomeComponentMapping[type]
 
return <TheHomePage pageContext={pageContext} />
}
 
HomePage.propTypes = {
type: PropTypes.string
}
 
HomePage.defaultProps = {
type: 'normal'
}
 
export default HomePage

再把带分页的首页弄一弄。

import React from 'react'
import { Link } from 'gatsby'
 
import Paginator from '../Paginator'
 
import './style.css'
 
const { Fragment } = React
 
const NormalHomePage = ({ pageContext }) => {
const {
group,
index,
pageCount 
} = pageContext
 
return <Fragment>
{group.map(({ node }) => (
<div className="normal-homepage-item" key={node.id}>
<h3><Link className="title" to={node.frontmatter.path}>{node.frontmatter.title}</Link></h3>
<small>Posted by {node.frontmatter.author} on {node.frontmatter.date}</small>
<br/>
<br/>
<div dangerouslySetInnerHTML={{__html: node.html.split('<!--more-->')[0]}}></div>
<Link to={node.frontmatter.path}>Read More</Link>
<br/>
</div>
))}
<Paginator index={index} pageCount={pageCount} relativeUrl="" />
</Fragment>
}
 
export default NormalHomePage

注:博文里需要有识别符 <!--more-->。之所以首页能只显示一部分,是因为使用这个识别符做了拆分。


7. 返回顶部

返回顶部的实现方式有很多种,这里只作为示例。

import React from 'react'
 
import './style.css'
 
class BackToTop extends React.Component {
constructor(props) {
super(props)
 
this.state = {
show: false
}
 
this.timer = undefined
this.scrollHandle = this.scrollHandle.bind(this)
}
 
componentDidMount() {
window.addEventListener('scroll', this.scrollHandle)
}
 
componentWillUnmount() {
window.removeEventListener('scroll', this.scrollHandle)
}
 
scrollHandle() {
clearTimeout(this.timer)
this.timer = setTimeout(() => {
this.setState({
show: document.body.scrollTop > 700 || document.documentElement.scrollTop > 700
})
}, 100)
}
 
render() {
return this.state.show && <div className="back-to-top">
<button onClick={() => { window.scrollTo(0, 0) }}>⬆︎</button>
</div>
}
}
 
export default BackToTop

8. 滚动条进度条

import React from 'react'
 
import './style.css'
 
class ScrollIndicator extends React.Component {
constructor(props) {
super(props)
 
this.scrollHandle = this.scrollHandle.bind(this)
}
 
componentDidMount() {
window.addEventListener('scroll', this.scrollHandle)
}
 
componentWillUnmount() {
window.removeEventListener('scroll', this.scrollHandle)
}
 
scrollHandle() {
let winScroll = document.body.scrollTop || document.documentElement.scrollTop
let height = document.documentElement.scrollHeight - document.documentElement.clientHeight
let scrolled = (winScroll / height) * 100
this.refs.progress_bar.style.width = `${scrolled}%`
}
 
render() {
return <div className="scroll-indicator">
<div ref="progress_bar" className="progress-bar"></div>
</div>
}
}
 
export default ScrollIndicator

9. 百度统计 & 被 Google 搜索

Google统计的脚本在国内有时候加载不成功,都懂得。

不废话,安装百度统计的中间件。

npm i gatsby-plugin-baidu-tongji

修改下配置文件 gatsby-config.js

...
plugins: [
...
{
resolve: 'gatsby-plugin-baidu-tongji',
options: {
siteid: 'FiJx5NYvSMLLCLCO9Ep9AmCEYpnhLZEo',
head: false
}
}
...
]
...

被 Google 搜索需要在 search.google.com 上注册自己的站点。

站点的验证方式很多,这里用举例 meta 方式。修改 src/components/seo.js

...
meta={[
...
{
name: `google-site-verification`,
content: 'axWre5Mc1WeCJHuCSLAALonVYdzjco_Ao__dvd3CsYX'
}
...
]}
...
`

10. 发布站点脚本 & CNAME 文件

运行如下命令:

gatsby build

待发布的站点就在 public 目录里了

为了发布方便做了个发布脚本 deploy.sh

#!/bin/bash
rm -rf ./.cache
rm -rf ./public/*
 
gatsby build
 
echo ""
echo "====>> publish version: $1 <<===="
echo ""
 
cd ./public
git add .
git commit -m "$1"
git push

注:发布前最好清理一下 public 目录,因为总是增量发布,所以会有很多历史文件,同一个功能只是 hash 有变化。

配置 package.json

...
"scripts"{
...
"deploy": "sh deploy.sh"
...
}
...

使用方法如下:

npm run deploy -- v0.0.1

另:如果自己有独立域名,还需要将 CNAME 文件放入发布目录。

只需要将 CNAME 文件放入 static/ 目录即可,脚本编译的时候会自动同步过去。


- THE END -