• [技术干货] 编辑技能:使用 Markdown 标记语言仅仅靠键盘也能完成排版,鼠标兄弟可以一边歇着了
    你可能不知道什么叫做富文本编辑器,什么叫做标记语言,但如果你有计划想成为一名 SaaS 服务商,又或者你想编写一下当前很火的 AI 提示词之类的,那么 Markdown 标记语言是你无法避开的「技术」。探索本文不会很深入去教你使用 Markdown 语言(本人也懂得不多),或者说 Markdown 根本也没有很深入的用法(虽然懂得不多,还是得装下去),为什么这么说呢,我们来对比一下,平时我们用 Office Word 或 WPS 文字设置文字作为标题1、标题2、标题3等样式,一般是这样操作:如果用 Markdown 来做同样的排版则是这样的:可以看出,在 WPS 是借助强大的富文本编辑器,结合鼠标的拖拽,就能很容易地完成排版。换成 Markdown 标记语言的话,貌似全程不需要怎样借助鼠标,就是输入一个个「# + 空格」,三个标题的样式排版就神奇般完成了。是的,这就是 Markdown 标记语言,用「# ` -」这些字符结合空格、回车来完成大部分的排版。我再举多几个例子,就能更加明白了。我在左边已经预置好文字,只要加上这些标记符,右边就能实时看到效果。全程只是用键盘,在已有文字附近输入一些简单的符号,就能完成样式的输出。特别是有序和无序排列,在 Office 当中没有「苦练」一段时间的鼠标,都不敢拖拉生成这种排序,而且按个回车还要小心翼翼,生怕破坏格式。在 Markdown 就没有那么矫情了,只要是按照标准输入的,输出就一定也是标准的。学了用在哪里这个 Markdown 标记语言不是新生的事物,它诞生于 2004年,在 Github 这个开源平台全面支持 Markdown 之后,IT圈就开始流行这个标记语言了。所以,我们作为 SaaS 服务商的身份,对这个语言的掌握是必要的。公域平台比如,我们在一些云平台社区,论坛发帖是支持 Markdown 语法的。在比较知名的问答平台,写个文章,也是支持 Markdown 语法的。这些平台,特别是 IT 相关的,几乎都开始兼容 Markdown 语法了。当然,Markdown 虽然创始人规范了一些使用符号,但是在实际的应用当中,许多平台或者开发者也会自定义一些符号,产生更多的效果,这个要仔细看每个平台的帮助说明。一旦掌握基本的原理,再去适应更多的符号也是相当于容易的。开源程序Markdown 文件的后缀名是 .md,在最大的开源平台 Github 上面,所有的项目文档说明 README.md 都是用 Markdown 标记语言编写的文档。比如流行的面板:1Panel 的说明文档。许多新的开源程序,比如一些论坛,或者博客程序,默认编辑器不再是之前的那些富文本 HTML 编辑器了,取代的就是支持 Markdown 语法的编辑器。Markdown 客户端在 Windows 平台,有许多支持 Markdown 语法的客户端,当然在 Mac 苹果端也有。Windows 比较著名的有:Typora,后来转成收费软件之后,也产生了许多取代的。比如:MarkText,还有火到不行的:Obsidian,后面有机会我再起篇章写这些客户端的应用。因为 Markdown 语法简单,通过简单的字符就能输出 HTML 排版,加上 CSS 主题,所输出的样式就十分灵活了。甚至,用 Markdown 写公众号推文也是可行的,只是要先在客户端写好,再通过转换样式拷贝上去。这也是在后面有机会分享给大家。当然,微软的 Visual Studio Code 这款免费的编辑器,装上插件,就是神一般存在的 Markdown 的利器,本文的预览演示就是用它生成的。
  • [其他] markdown的格式代码
    Markdown是一种轻量级的标记语言,它允许人们使用易读易写的纯文本格式编写文档。Markdown的语法简单明了,易于阅读和编写。以下是一些常用的Markdown格式代码:标题:使用#表示一级标题,##表示二级标题,以此类推。例如:# 一级标题 ## 二级标题 ### 三级标题加粗:使用两个*或_包围文本,表示加粗。例如:**加粗文本** __加粗文本__斜体:使用一个*或_包围文本,表示斜体。例如:*斜体文本* _斜体文本_无序列表:使用-或+开头的行表示无序列表项。例如:- 列表项1 - 列表项2 - 列表项3有序列表:使用数字和.开头的行表示有序列表项。例如:1. 列表项1 2. 列表项2 3. 列表项3链接:使用[链接文字](链接地址)表示链接。例如:百度图片:使用![图片描述](图片地址)表示图片。例如:!示例图片引用:使用>开头的行表示引用。例如:> 这是一段引用文本代码块:使用三个反引号(`)包围代码,可以指定代码的语言。例如:print("Hello, World!")分割线:使用三个或以上的-或*表示分割线。例如:--- ***以上就是Markdown的一些常用格式代码,通过这些简单的语法,我们可以快速地编写出美观且易于阅读的文档。
  • [技术干货] Markdown 高级技巧【转载】
    Markdown 高级技巧支持的 HTML 元素不在 Markdown 涵盖范围之内的标签,都可以直接在文档里面用 HTML 撰写。目前支持的 HTML 元素有: 等 ,如:使用 Ctrl+Alt+Del 重启电脑输出结果为:转义Markdown 使用了很多特殊符号来表示特定的意义,如果需要显示特定的符号则需要使用转义字符,Markdown 使用反斜杠转义特殊字符:**文本加粗**\*\* 正常显示星号 \*\*输出结果为:Markdown 支持以下这些符号前面加上反斜杠来帮助插入普通的符号:\ 反斜线` 反引号* 星号_ 下划线{} 花括号[] 方括号() 小括号# 井字号+ 加号- 减号. 英文句点! 感叹号公式Markdown Preview Enhanced 使用 KaTeX 或者 MathJax 来渲染数学表达式。KaTeX 拥有比 MathJax 更快的性能,但是它却少了很多 MathJax 拥有的特性。你可以查看 KaTeX supported functions/symbols 来了解 KaTeX 支持那些符号和函数。默认下的分隔符:$...$ 或者 \(...\) 中的数学表达式将会在行内显示。$$...$$ 或者 \[...\] 或者 ```math 中的数学表达式将会在块内显示。$$\begin{Bmatrix}a & b \\c & d\end{Bmatrix}$$$$\begin{CD}A @>a>> B \\@VbVV @AAcA \\C @= D\end{CD}$$输出结果为:Markdown 表格1 篇笔记 写笔记adc928***528@qq.com  参考地址1125typora 画流程图、时序图(顺序图)、甘特图复制以下代码使用 typora 的源码模式粘贴到编辑器中查看效果:以下几个实例效果图如下:1、横向流程图源码格式:```mermaidgraph LRA[方形] -->B(圆角)B --> C{条件a}C -->|a=1| D[结果1]C -->|a=2| E[结果2]F[横向流程图]```2、竖向流程图源码格式:```mermaidgraph TDA[方形] --> B(圆角)B --> C{条件a}C --> |a=1| D[结果1]C --> |a=2| E[结果2]F[竖向流程图]```3、标准流程图源码格式:```flowst=>start: 开始框op=>operation: 处理框cond=>condition: 判断框(是或否?)sub1=>subroutine: 子流程io=>inputoutput: 输入输出框e=>end: 结束框st->op->condcond(yes)->io->econd(no)->sub1(right)->op```4、标准流程图源码格式(横向):```flowst=>start: 开始框op=>operation: 处理框cond=>condition: 判断框(是或否?)sub1=>subroutine: 子流程io=>inputoutput: 输入输出框e=>end: 结束框st(right)->op(right)->condcond(yes)->io(bottom)->econd(no)->sub1(right)->op```5、UML时序图源码样例:```sequence对象A->对象B: 对象B你好吗?(请求)Note right of 对象B: 对象B的描述Note left of 对象A: 对象A的描述(提示)对象B-->对象A: 我很好(响应)对象A->对象B: 你真的好吗?```6、UML时序图源码复杂样例:```sequenceTitle: 标题:复杂使用对象A->对象B: 对象B你好吗?(请求)Note right of 对象B: 对象B的描述Note left of 对象A: 对象A的描述(提示)对象B-->对象A: 我很好(响应)对象B->小三: 你好吗小三-->>对象A: 对象B找我了对象A->对象B: 你真的好吗?Note over 小三,对象B: 我们是朋友participant CNote right of C: 没人陪我玩```7、UML标准时序图样例:```mermaid%% 时序图例子,-> 直线,-->虚线,->>实线箭头sequenceDiagramparticipant 张三participant 李四张三->王五: 王五你好吗?loop 健康检查王五->王五: 与疾病战斗endNote right of 王五: 合理 食物看医生...李四-->>张三: 很好!王五->李四: 你怎么样?李四-->王五: 很好!```8、甘特图样例:```mermaid%% 语法示例ganttdateFormat YYYY-MM-DDtitle 软件开发甘特图section 设计需求 :done, des1, 2014-01-06,2014-01-08原型 :active, des2, 2014-01-09, 3dUI设计 : des3, after des2, 5d未来任务 : des4, after des3, 5dsection 开发学习准备理解需求 :crit, done, 2014-01-06,24h设计框架 :crit, done, after des2, 2d开发 :crit, active, 3d未来任务 :crit, 5d耍 :2dsection 测试功能测试 :active, a1, after des3, 3d压力测试 :after a1 , 20h测试报告 : 48h```效果图如下:转载自https://www.runoob.com/markdown/md-advance.html
  • [技术干货] Markdown 表格【转载】
    Markdown 表格Markdown 制作表格使用 | 来分隔不同的单元格,使用 - 来分隔表头和其他行。语法格式如下:| 表头 | 表头 || ---- | ---- || 单元格 | 单元格 || 单元格 | 单元格 |以上代码显示结果如下:对齐方式我们可以设置表格的对齐方式:-: 设置内容和标题栏居右对齐。:- 设置内容和标题栏居左对齐。:-: 设置内容和标题栏居中对齐。实例如下:| 左对齐 | 右对齐 | 居中对齐 || :-----| ----: | :----: || 单元格 | 单元格 | 单元格 || 单元格 | 单元格 | 单元格 |以上代码显示结果如下:转载自https://www.runoob.com/markdown/md-table.html
  • [技术干货] Markdown 图片【转载】
    Markdown 图片Markdown 图片语法格式如下:![alt 属性文本](图片地址)![alt 属性文本](图片地址 "可选标题")开头一个感叹号 !接着一个方括号,里面放上图片的替代文字接着一个普通括号,里面放上图片的网址,最后还可以用引号包住并加上选择性的 'title' 属性的文字。使用实例:![RUNOOB 图标](http://static.runoob.com/images/runoob-logo.png)![RUNOOB 图标](http://static.runoob.com/images/runoob-logo.png "RUNOOB")显示结果如下:当然,你也可以像网址那样对图片网址使用变量:这个链接用 1 作为网址变量 [RUNOOB][1].然后在文档的结尾为变量赋值(网址)[1]: http://static.runoob.com/images/runoob-logo.png显示结果如下:Markdown 还没有办法指定图片的高度与宽度,如果你需要的话,你可以使用普通的 标签。显示结果如下:转载自https://www.runoob.com/markdown/md-image.html
  • [技术干货] Markdown 链接【转载】
    Markdown 链接链接使用方法如下:[链接名称](链接地址)或者<链接地址>例如:这是一个链接 [菜鸟教程](https://www.runoob.com)显示结果如下:直接使用链接地址:显示结果如下:高级链接我们可以通过变量来设置一个链接,变量赋值在文档末尾进行:这个链接用 1 作为网址变量 [Google][1]这个链接用 runoob 作为网址变量 [Runoob][runoob]然后在文档的结尾为变量赋值(网址)[1]: http://www.google.com/[runoob]: http://www.runoob.com/显示结果如下:转载自https://www.runoob.com/markdown/md-link.html
  • [技术干货] Markdown 代码【转载】
    Markdown 代码如果是段落上的一个函数或片段的代码可以用反引号把它包起来(`),例如:`printf()` 函数显示结果如下:代码区块代码区块使用 4 个空格或者一个制表符(Tab 键)。实例如下:显示结果如下:你也可以用 ``` 包裹一段代码,并指定一种语言(也可以不指定):```javascript$(document).ready(function () {alert('RUNOOB');});```显示结果如下:转载自https://www.runoob.com/markdown/md-code.html
  • [技术干货] Markdown 区块【转载】
    Markdown 区块Markdown 区块引用是在段落开头使用 > 符号 ,然后后面紧跟一个空格符号:> 区块引用> 菜鸟教程> 学的不仅是技术更是梦想显示结果如下:另外区块是可以嵌套的,一个 > 符号是最外层,两个 > 符号是第一层嵌套,以此类推:> 最外层> > 第一层嵌套> > > 第二层嵌套显示结果如下:区块中使用列表区块中使用列表实例如下:> 区块中使用列表> 1. 第一项> 2. 第二项> + 第一项> + 第二项> + 第三项显示结果如下:列表中使用区块如果要在列表项目内放进区块,那么就需要在 > 前添加四个空格的缩进。列表中使用区块实例如下:* 第一项> 菜鸟教程> 学的不仅是技术更是梦想* 第二项显示结果如下:转载自https://www.runoob.com/markdown/md-block.html
  • [技术干货] Markdown 列表【转载】
    Markdown 列表Markdown 支持有序列表和无序列表。无序列表使用星号(*)、加号(+)或是减号(-)作为列表标记,这些标记后面要添加一个空格,然后再填写内容:* 第一项* 第二项* 第三项+ 第一项+ 第二项+ 第三项- 第一项- 第二项- 第三项显示结果如下:有序列表使用数字并加上 . 号来表示,如:1. 第一项2. 第二项3. 第三项显示结果如下:列表嵌套列表嵌套只需在子列表中的选项前面添加两个或四个空格即可:1. 第一项:- 第一项嵌套的第一个元素- 第一项嵌套的第二个元素2. 第二项:- 第二项嵌套的第一个元素- 第二项嵌套的第二个元素显示结果如下:转载自https://www.runoob.com/markdown/md-lists.html
  • [技术干货] Markdown 段落【转载】
    Markdown 段落Markdown 段落没有特殊的格式,直接编写文字就好,段落的换行是使用两个以上空格加上回车。当然也可以在段落后面使用一个空行来表示重新开始一个段落。字体Markdown 可以使用以下几种字体:*斜体文本*_斜体文本_**粗体文本**__粗体文本__***粗斜体文本***___粗斜体文本___显示效果如下所示:分隔线你可以在一行中用三个以上的星号、减号、底线来建立一个分隔线,行内不能有其他东西。你也可以在星号或是减号中间插入空格。下面每种写法都可以建立分隔线:**** * ******- - -----------显示效果如下所示:删除线如果段落上的文字要添加删除线,只需要在文字的两端加上两个波浪线 ~~ 即可,实例如下:RUNOOB.COMGOOGLE.COM~~BAIDU.COM~~显示效果如下所示:下划线下划线可以通过 HTML 的  标签来实现:带下划线文本显示效果如下所示:脚注脚注是对文本的补充说明。Markdown 脚注的格式如下:[^要注明的文本]以下实例演示了脚注的用法:创建脚注格式类似这样 [^RUNOOB]。[^RUNOOB]: 菜鸟教程 -- 学的不仅是技术,更是梦想!!!演示效果如下:转载自https://www.runoob.com/markdown/md-paragraph.html
  • [技术干货] Markdown 标题【转载】
    Markdown 标题Markdown 标题有两种格式。1、使用 = 和 - 标记一级和二级标题= 和 - 标记语法格式如下:我展示的是一级标题=================我展示的是二级标题-----------------显示效果如下图:使用 # 号标记使用 # 号可表示 1-6 级标题,一级标题对应一个 # 号,二级标题对应两个 # 号,以此类推。# 一级标题## 二级标题### 三级标题#### 四级标题##### 五级标题###### 六级标题显示效果如下图:转载自https://www.runoob.com/markdown/md-title.html
  • [技术干货] Markdown 教程【转载】
    Markdown 教程Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档。Markdown 语言在 2004 由约翰·格鲁伯(英语:John Gruber)创建。Markdown 编写的文档可以导出 HTML 、Word、图像、PDF、Epub 等多种格式的文档。Markdown 编写的文档后缀为 .md, .markdown。Markdown 应用Markdown 能被使用来撰写电子书,如:Gitbook。当前许多网站都广泛使用 Markdown 来撰写帮助文档或是用于论坛上发表消息。例如:GitHub、简书、reddit、Diaspora、Stack Exchange、OpenStreetMap 、SourceForge等。编辑器本教程将使用 VSCode 编辑器来讲解 Markdown 的语法,VSCode 支持 MacOS 、Windows、Linux 平台,且包含多种主题。VSCode 默认集成了 Markdown 文档编辑插件,原生就支持高亮 Markdown 的语法。VSCode(全称:Visual Studio Code)是一款由微软开发且跨平台的免费源代码编辑器。VScode 安装教程:https://www.runoob.com/w3cnote/vscode-tutorial.htmlVScode 官网地址:https://code.visualstudio.com/VSCode 实时预览还需要执行 Markdown: Open Preview to the Side 命令来实现。在命令窗口输入 Markdown: Open Preview to the Side 命令:最终效果:如果你需要将 markdown 转为 PDF、图片、HTML 等格式也可以安装对应的插件来实现。你也可以使用我们的在线编辑器来测试:https://c.runoob.com/front-end/712。测试实例接下来的测试中,我们先在 VSCode 下安装 Markdown Preview Enhanced 插件来实现更强大的功能。点击右侧栏扩展按钮,查找Markdown Preview Enhanced 插件,点击安装:安装完成后重启 VSCode。在 RUNOOB.md 输入以下代码:# RUNOOB Markdown Test## Hello World!将该代码格式粘贴到文件 RUNOOB.md 上,效果如下:在预览框中右击鼠标还提供了各种导出功能:转载自https://www.runoob.com/markdown/md-tutorial.html
  • [分享交流] markdown数学公式一览表
    $(A,A)=(A,A)$ # markdown数学公式基础语法 ## 单行公式 公式内容分别用`$`包起来。 示例:`$E=mc^2$` 效果:$E=mc^2$ 注意:`$`左右不带空格 ## 多行公式 公式内容左右分别用`$$`包起来。 示例:`$$E=mc^2$$` 效果: $$E=mc^2$$ 此时公式独占一行。 ## markdown常用数学公式一览表 |运算符|说明|举例|举例代码| |-------|:----:|:----:|:----:| |+ | 加 | $x+y$ | `$x+y$` | |- | 减 | $x-y$ | `$x-y$` | |\times| 乘 | $x \times y$ | `$x \times y$` | |\ast | 乘 |$x \ast y$ | `$x \ast y$` | |\div | 除 |$x \div y$ | `$x \div y$` | |\frac | 分数 | $\frac{x}{y}$ | `$\frac{x}{y}$` | |\infty| 无穷| $\infty$|`$\infty$`| |^ | 上标 |$x^y$ | `$x^y$` | |_ | 下标 |$x_y$ | `$x_y$` | |\sqrt |开方 |$\sqrt[x]{y+1}$ | `$\sqrt[x]{y+1}$` | |\pm |加减 |$x \pm y$ |`$x \pm y$` | |\mp |减加 |$x \mp y$ |`$x \mp y$` | |\log |对数 |$\log_2{y}$ | `$\log_2{y}$` | |\lim |极限 |$\lim_{x \to 3}$ | `$\lim_{x \to 3}$` | |\displaystyle |块公式格式 | $\displaystyle \lim_{x \to 3}$ |`$\displaystyle \lim_{x \to 3}$` | |\sum |求和 |$\sum_1^{\infty}$ |`$\sum_1^{\infty}$` | |\int |积分 |$\int_1^{\infty}$ | `$\int_1^{\infty}$` |### 更多公式请查阅katex官网:https://katex.org/docs/supported.html
  • [技术干货] Markdown
    前言写过博客或者github上面的文档的,应该知道Markdown语法的重要性,不知道的朋友们也别着急,一篇博客轻松搞定Markdown语法。话说这个语法超级简单,一看就会,不信你点进来看看。1. 快捷键跳转到目录功能快捷键加粗Ctrl + B斜体Ctrl + I引用Ctrl + Q插入链接Ctrl + L插入代码Ctrl + K插入图片Ctrl + G提升标题Ctrl + H有序列表Ctrl + O无序列表Ctrl + U横线Ctrl + R撤销Ctrl + Z重做Ctrl + Y
  • 上手 Gatsby 入门教程
    Gatsby 项目结构建议使用 Starter 修改着理解 Gatsby,我用的是 Gatsby + Netlify CMS Starter。完整的 Gatsby 项目结构可以看文档,这里针对搭建博客用到的功能说明一下。    /src/pages 目录下的组件会被生成同名页面。    /src/templates 目录下放渲染数据的模板组件,如渲染 Markdown 文章,在其它博客系统中一般叫 layout。    /src/components 一般放其它共用的组件。    /static 放其它静态资源,会跳过 Webpack 直接复制过去。接下来是两个比较常用的配置文件,需要修改时参考 Starter 改即可。    /gatsby-config.js 基本用来配置两个东西:    siteMetadata 放一些全局信息,这些信息在每个页面都可以通过 GraphQL 获取到。    plugins 配置插件,这个按用到时按该插件文档说明弄即可。    /gatsby-node.js 可以调用 Gatsby node APIs干一些自动化的东西。一般有两个常用场景:        添加额外的配置,比如为 Markdown 文章生成自定义路径。        生成 /src/pages 以外的页面文件,如为每个 Markdown 文章生成页面文件。    此外还有两个不那么常用的配置文件。        /gatsby-browser.js 可以调用 Gatsby 浏览器 APIs,一般插件才会用到,如滚动到特定位置。        /gatsby-ssr.js 服务器渲染的配置,一般也是插件才用到。    这就是搭建 Gatsby 博客的基本结构了,可以看到非常简单,且因为其丰富的生态,其它底层接口基本不需要用到。但接下来还是会有一些小坑,第一个便是 GraphQL,我们将马上来分析。为什么用 GraphQL    在上一节介绍了选择 Gatsby 的原因,其中提到了 Gatsby 使用 GraphQL 。大家可能会有疑惑,不是建静态博客么,怎么会有 GraphQL?难道还要部署服务器?    其实这里 GraphQL 并不是作为服务器端部署,而是作为 Gatsby 在本地管理资源的一种方式。    通过 GraphQL 统一管理实际上非常方便,因为作为一个数据库查询语言,它有非常完备的查询语句,与 JSON 相似的描述结构,再结合 Relay 的 Connections 方式处理集合,管理资源不再需要自行引入其它项目,大大减轻了维护难度。带魔法的 GraphQL    这里也是 Gatsby 的第一个坑。在 Gatsby 中,根据 js 文件的位置不同,使用 GraphQL 有两种形式,且 Gatsby 对其做了魔法,在 src /pages 下的页面可以直接 export GraphQL 查询,在其它页面需要用 StaticQuery 组件或者 useStaticQuery hook。    这里面查询语句虽然写的是字符串,但其实这些查询语句不会出现在最终的代码中,Gatsby 会先对其抽取。    个人其实不太喜欢魔法,因为会增加初学者的理解难度。但不得不承认魔法确实很方便,就是用了魔法的项目应该在文档最显眼的地方说明一遍。快速上手 GraphQL    GraphQL 结构跟最终数据很相似,基本语法也非常简单,看看官方文档即可。一个快速上手的方式是访问项目开发时(默认 http://localhost:8000)的 /___graphql 页面,通过 GraphiQL 编辑器右侧可以浏览所有能够查询的资源。    另一个需要理解的是 Relay 的 Connections 概念,你会发现 Gatsby 里所有的数据集合都是以这种方式查询。推荐阅读 Apollo 团队分享的文章。    对 Connections 细致的理解往往是实现分页等底层需求时才需要,而这些均有插件完成。一般使用时只需要知道集合里每个项目的数据在 edges.node 中,同时通过 GraphiQL 浏览其它可以使用的数据。如对于 Markdown 文章,相应插件提供了字数统计以及阅读时长等数据,均可通过 GraphQL 直接获取。Debug GraphQL    Gatsby 魔法带来的另外一个坑是 GraphQL 报错信息不全,可能会默默被吞掉,也可能无法定位到最终文件。    我在修改 starter 时踩到一个坑是复制组件时忘了修改 static query 查询语句的名称,导致重名报错。    避免错误最好方式是在 GraphiQL 编辑器中写好运行无误再复制到组件中。Remark 插件坑    Gatsby 中处理 markdown 最常用也是默认的插件是 gatsby-transformer-remark。这个插件对 markdown 文件解析后会生成 MarkdownRemark GraphQL 节点,其中 front matters 数据也会被解析出来。同时 MarkdownRemark 的集合对应为 allMarkdownRemark connections。    对于 connections 节点我们一般可以用 sort 和 filter 来筛选处理数据(可在 GraphiQL 编辑器中浏览),这里有一个坑便是如果要处理 front matters 数据,它们必须存在所有查询的 markdown 文件上并且具有相同的类型,插件才会生成相应的 fields,否则可能会抛出异常或者更糟糕的,默默失败了。    避免方式同上,先在 GraphiQL 编辑器中运行一遍,看看筛选的结果是否正确。    另外一种处理方式是在 /gatsby-node.js 中通过 onCreateNode 钩子,在生成 markdown 相关节点时手工处理,确保节点存在。    这在实现草稿和上下篇的时候会用到,具体例子我会在后续章节中提到。为什么选择 Netlify CMS    搭建 Gatsby 博客其实不需要 CMS 都是可以的,编写 Markdown 然后 build 即可。但这么做还是略嫌不便,通过 CMS 一般可以在一个可视化的在线环境中编辑文章,然后一键即可发布。    Gatsby 主流的两个 CMS 是 Contentful 和 Netlify CMS。    对于 Contentful 来说,文章是放在 Contentful 的服务器上的,管理也是通过 Contentful 提供的工具。当然其质量还是不错的,喜欢的可以参照官方的教程搭建。    Netlify CMS 是跟项目一起发布的,默认是在 /admin 页面下。文章也是存在源项目中,就是原来默认的 Markdown 文件。Netlify CMS 借助 Oauth 把写好的 Markdown 文件推送到项目源码的仓库上,再配合 Netlify 检测仓库变动自动构建发布。当然后者也不是必须的,可以换其它方式自动构建。    Netlify CMS 的优点是开源免费,文章跟项目源码在一起,界面可以高度自定义,甚至可以自行扩充 React 组件,基本满足简单的博客编写需求。配置 Netlify CMS    如果用官方的 starter配置将会非常简单。此 starter 默认使用 Github 作为仓库,Netlify 作为自动构建服务器。配置 Widgets    默认的 /static/admin/config.yml 已经配置好了大部分,如果对文章 Markdown 添加了自定义的 front matters 则需要再做些细调。    Widgets 代表了在 CMS 中可输入的模块,官方为常见的类型都提供了默认的 widgets ,没有满足的也可以自定义。    如我的博客中每篇文章都有一个 quote 域放些引用文字,那么在配置中添加上 fields: - label: "Quote" name: "quote" widget: "object" fields: - {label: "Content", name: "content", widget: "text", default: "", required: false} - {label: "Author", name: "author", widget: "string", default: "", required: false} - {label: "Source", name: "source", widget: "string", default: "", required: false}    如此即可在 CMS 中填写相关信息。配置预览    CMS 中提供了文章预览界面,如果需要自定义只需修改 /src/cms/ 下相应的文件即可,就是简单的 React 组件。    以上便是 Netlify CMS 最常用的配置,只需简单的修改博客现在就能跑起来了。接下来我们会通过实现草稿模式和上下篇文章来深入理解 Gatsby 的机制。    迁移博客需要考虑的一个重要问题便是路径兼容。我们当然不希望迁移后原有的链接无法访问,这不仅影响到 SEO ,更带来了不好的用户访问体验。本文将聊聊怎么让 Gatsby 兼容 Jekyll 式路径。Gatsby 如何生成特定页面    一般来说,在 /src/pages/ 目录下的组件会自动生成相应路径的页面,但如果是其它类型的文件就不会了。我们可以通过 Gatsby 的 Node APIs 来生成特定页面。    在 /gatsby-node.js 中配置 Gatsby Node APIs,如果项目是基于 starter 的话你很可能会发现里面已经有相应的配置。    我们通过声明 exports.createPages 钩子来配置页面生成,在回调中通过调用 actions.createPage 来生成某个指定页面。这个方法接受一个配置参数,其中的 path 域代表了生成页面的路径。 exports.createPages = ({ actions, graphql }) => { actions.createPage({ path, // ... }) }指定博客页面    那么我们怎么知道该生成哪些页面呢?这里通过 exports.createPages 回调中的 graphql 来查询 Markdown 文件。 exports.createPages = ({ actions, graphql }) => { const { createPage } = actions return graphql(` { allMarkdownRemark(sort: { order: ASC, fields: [frontmatter___date] }) { edges { node { id fields { slug } frontmatter { path title layout } } } } } `).then(result => { if (result.errors) { result.errors.forEach(e => console.error(e.toString())) return Promise.reject(result.errors) } // ... }) }    Netlify CMS 会在 Markdown front matters 中的 path 域生成路径。根据默认的 /static/admin/config.yml 我们的路径应该是 /blog/{{year}}-{{month}}-{{day}}-{{slug}}/ ,这个可能跟旧博客不一样,如 Jekyll 是 /{{year}}/{{month}}/{{day}}/{{slug}}/ 。修改 Markdown 节点    在 Remark 插件生成的 Markdown 节点中,我们可以往 fields 域放一些自定义的变量。这里我们把自定义的路径存到 fields.slug 中。    通过 /gatsby-node.js 中的 exports.onCreateNode 钩子我们可以在生成节点的时候进行拦截处理。你可能发现文件里面已经有一些配置的代码了,我们这里只关注 Markdown 相关的。 exports.onCreateNode = ({ node, actions, getNode }) => { const { createNodeField } = actions if (node.internal.type === `MarkdownRemark`) { // Jeykll style post path const filepath = createFilePath({ node, getNode }) createNodeField({ node, name: 'slug', value: filepath.replace( /^\/blog\/([\d]{4})-([\d]{2})-([\d]{2})-/, '/$1/$2/$3/' ) }) } }    我们把原有的路径值换成了自定义值并存在了 fileds.slug 中。创建页面    回到我们前面的查询,得到需要的数据之后只需要对每个页面调用 actions.createPage 即可。  exports.createPages = ({ actions, graphql }) => { const { createPage } = actions return graphql(` { allMarkdownRemark(sort: { order: ASC, fields: [frontmatter___date] }) { edges { node { id fields { slug } frontmatter { path title layout } } } } } `).then(result => { if (result.errors) { result.errors.forEach(e => console.error(e.toString())) return Promise.reject(result.errors) } const { edges } = result.data.allMarkdownRemark const options = edges.map(edge => ({ path: edge.node.fields.slug, title: edge.node.frontmatter.title, component: path.resolve( `src/templates/${edge.node.frontmatter.layout}.js` ), // additional data can be passed via context context: { id: edge.node.id } })) options.forEach(option => createPage(option)) }) }     也许你会问为什么不在这里直接计算自定义路径而是要存到 fields.slug 中。这是因为这个路径我们可能还会在其它地方用到,存起来就不必多处计算了。    上面代码中可以注意到还有个 context 域,这个域中的数据会被传到 component 的 props 中。这样我们在模板组件中通过 pageContext.id 便可判断当前渲染的文件。    通过实现自定义路径基本上可以了解 Gatsby 页面生成的方式了。下节中我会继续谈谈其它个性化的配置,如草稿模式和显示上下篇博文。草稿模式    草稿模式即可以将文章保存为草稿而不被渲染出来。方式是在 front matters 中设置一个 draft 布尔域,以此域作为渲染参考。    坑    这里有一个地方需要注意,前面文章提过,Markdown 插件需要所有文章中都有 draft 域且都是布尔类型才会生成相应的 GraphQL 查询。如果是新的博客这个问题不大,如果是迁移过来的,有两个解决方式,第一个是手动写个脚本给文章都补上域,另一个是利用 Gatsby 的 Node APIs 在 fields 上生成特定域,鲁棒性更好些。自动生成域    观察 Remark 插件生成的 GraphQL 类型,我们可以发现,front matters 都被放在 frontmatter 域中,而与之同级的有一个前面文章提到过的 fields 域,用来放自定义生成的数据。    Gatsby 在生成 GraphQL 节点时提供了钩子 onCreateNode,我们利用这个钩子往 fields 中放自定义的数据。    编辑 /gatsby-node.js ,如果是用了 starter 的话这里很可能已经有其它的代码,已有的不需要动,添加我们需要的即可。 exports.onCreateNode = ({ node, actions, getNode }) => { const { createNodeField } = actions if (node.internal.type === `MarkdownRemark`) { createNodeField({ node, name: 'draft', value: Boolean(node.frontmatter.draft) }) } }    如此 fields 中就保证了会有 draft 这个域了。过滤草稿    有了标记之后,在生成页面的地方我们就需要过滤草稿。    首先是普通的文章页面生成,这个是在 createPages 钩子中,如果你的博客只有文章用到 Markdown 的话,可以在 GraphQL 查询中直接过滤,否则我们用前面文章的方法,先取所有 Markdown 文件再根据渲染的模板来分别处理各种类型的文章。    注意我把模板域的名字换成了自己更习惯的 layout,原来的 starter 中应该叫 templateKey。修改其实也很简单,搜索所有文件替换关键字即可。 options .filter( (_, i) => !( edges[i].node.frontmatter.layout === 'blog-post' && edges[i].node.fields.draft ) ) .forEach(option => createPage(option))    我在主页中也列举了最近的几篇文章,这里也需要过滤草稿,可以直接在 GraphQL 中过滤。 query IndexQuery { latestPosts: allMarkdownRemark( sort: { order: DESC, fields: [frontmatter___date] } filter: { fields: { draft: { ne: true } } frontmatter: { layout: { eq: "blog-post" } } } limit: 5 ) { edges { node { excerpt(pruneLength: 200) id fields { slug } frontmatter { title description layout date(formatString: "MMMM DD, YYYY") } } } } }    其它地方同理。上下篇    在文章页面中我们通常会加入上下篇来引导继续浏览。这里我们同样在 createPages 钩子中处理,但这回我们添加到 context 域中,这个域里的数据会作为 props 传到模板组件中。    在 createPage 生成文章页面前添加处理代码计算上下篇: options .filter( (_, i) => edges[i].node.frontmatter.layout === 'blog-post' && !edges[i].node.fields.draft ) .forEach((option, i, blogPostOptions) => { option.context.prev = i === 0 ? null : { title: blogPostOptions[i - 1].title, path: blogPostOptions[i - 1].path } option.context.next = i === blogPostOptions.length - 1 ? null : { title: blogPostOptions[i + 1].title, path: blogPostOptions[i + 1].path } })    然后在文章的 /src/templates/blog-post.js 组件里,接收 pageContext props,就可以使用上面传入的数据了。这是我的例子。    通过实现这几个功能我们了解了 Gatsby 页面生成的方式以及其 Node APIs 的基本使用。Gatsby 的功能远不止这些,官方文档写得非常详细,需要实现其它功能建议先去看看有无现有的例子。本系列到这里暂告一段落,谢谢你的阅读,希望能对你搭建 Gatsby 博客有所帮助。