今天開始把網頁跟Contentful做連結。
Editor: 文章編輯者(雖然可能只有一人)
Post: 文章內容(slug屬性是到時候我們拿來當作文章的路由名稱使用)
Head: 首頁Header的文字以及圖片
完成後,新增會用到的圖片至Media,並且至Content新增一筆Head的資料,一筆Editor,跟幾筆Post,作為等等要給Gatsbyby抓的資料。
gatsby-source-contentful
這個plugin,並且我們需要'gatsby-transformer-remark'
來幫助我們將markdown格式的資料進行轉換成html格式,而我們Post的內容部分就會以markdown的格式傳遞,因此會用到這個Gatsby提供的方便工具。執行:npm install --save gatsby-source-contentful
和
'gatsby-transformer-remark',
並且在gatsby-config.js
的plugins中加入
{
resolve: `gatsby-source-contentful`,
options: {
spaceId: {SPACE ID},
accessToken: {DELIVERY ACCESS TOKEN},
}
},
'gatsby-transformer-remark',
token的獲取方法在Day19.用Gatsby+Contentful五分鐘內做出一個部落格吧中有說明。
gatsby develop
,http://localhost:8000/___graphql中執行:{
allContentfulPost {
edges {
node {
title
subTitle
slug
publishDate(formatString: "MMMM Do, YYYY") #回傳指定格式的日期
image {
file {
url
}
}
author {
name
}
tags
body {
#childMarkdownRemark這個field是因為安裝gatsby-source-contentful才產生的,不然原本只能抓到markdown的格式
childMarkdownRemark {
html
}
}
}
}
}
}
就可以輕易抓到我們要的資料了。
此外,可以觀察一下左邊Explore的部分:
Gatsby已經幫我們創好了Contentful資料的query field了,如果不知道語法怎麼下,就點點看,它就會幫你完成語法了,不會太困難。
能夠做到這麼方便的功能,正是因為Gatsby在建置階段便已經從Contentful抓完資料了,但也因為如此,如果contentful資料有更新,就必須重新啟動Gatsby。
gatsby-node.js
:const Promise = require('bluebird')
const path = require('path')
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
// 須回傳promise物件,因為graphql查詢為非同步事件。
return new Promise((resolve, reject) => {
resolve(
graphql(
`
{
allContentfulPost {
edges {
node {
title
slug
}
}
}
}
`
).then(result => {
if (result.errors) {
console.log(result.errors)
reject(result.errors)
}
// 根據抓到的文章slug來創建文章頁面,並且使用我們的post-template.js樣板
const posts = result.data.allContentfulPost.edges
posts.forEach((post) => {
createPage({
path: `/blog/${post.node.slug}/`,
component: path.resolve('./src/components/post-template.js'),
// 將slug傳遞過去,作為頁面抓取文章資料的識別符(當然,這裡創建頁面的同時把所需要的資料一次傳過去也是另一種方法)
context: {
slug: post.node.slug
},
})
})
})
)
})
}
如此一來,頁面便會在建置時被創出來了。
重新執行gatsby develop
,在網址後面亂打一些字來檢查一下:
http://127.0.0.1:8000/hkjh
完成~
import React from 'react'
export (props)=>{
return <div>{props.data.example.name}<div>
}
export const pageQuery = graphql`
query {
example {
name
}
}
`
於是,我們修改src/components/post-template.js
import React from "react"
import Layout from "./layout"
const PostPage = (props) => {
const post = props.data.contentfulPost
return (
<Layout>
<header className="masthead" style={{backgroundImage: `url('${post.image.file.url}')`}}>
<div className="overlay"></div>
<div className="container">
<div className="row">
<div className="col-lg-8 col-md-10 mx-auto">
<div className="post-heading">
<h1>{post.title}</h1>
<h2 className="subheading">{post.subTitle}</h2>
<span className="meta">Posted by {post.author.name} on {post.publishDate}</span>
</div>
</div>
</div>
</div>
</header>
<article>
<div className="container">
<div className="row">
<div className="col-lg-8 col-md-10 mx-auto" dangerouslySetInnerHTML={{
__html: post.body.childMarkdownRemark.html,
}}> {/*這個語法是為了防止CSRF攻擊,在JSX中放入HTML語法時,你必須確定很確定要放上去的資料是安全無誤的,以免你做一些蠢事,或被有心人士鑽漏洞*/}
</div>
</div>
</div>
</article>
<hr/>
</Layout>
)}
export default PostPage
export const pageQuery = graphql`
query PostBySlug($slug: String!) {
contentfulPost(slug: { eq: $slug }) {
contentful_id
title
subTitle
slug
publishDate(formatString: "MMMM Do, YYYY")
image {
file {
url
}
}
author {
name
}
tags
body {
childMarkdownRemark {
html
}
}
}
}
`
查詢語法的部分,使用了一個引入$slug參數的查詢式,Gatsby便會把剛剛gatsby-node.js傳過來的slug帶入查詢式,功能十分強大!
到這邊,頁面就完成了~
我們的下一步,是要在index頁面顯示文章列表,並做出分頁。
部落格實作文章的每一篇都會commit一次,需要的人可以自行抓下來。
github