在 github.io 上搭建自己的博客操作笔记和遇到的一些问题
博客使用注意事项
博客项目搭建参考 Github 官方文档
博客编写需要遵循 jekyll 的规范,请参考 jekyll 官网文档
创建文章
博客的项目目录为 owenliu1122.github.io
,
发布博客数据文件到 _post
目录下即可
⚠️ 注意:文件名假定为2019-02-26-hello-world.html。(注意,文件名必须为 “年-月-日-文章标题.后缀名” 的格式。如果网页代码采用 html 格式,后缀名为html;如果采用 markdown 格式,后缀名为md。)
上传图片
如果图片放在 _post
目录下,当项目 build 之后,图片是没办法正确显示的,例如会报如下错误:
1 |
|
所以这里需要使用项目下的绝对路径的方式解决这个问题,
-
首先在项目的跟路径下创建目录
images
:1
mkdir images
-
然后把资源图片放到
images
目录下1
2cd images mv ../_post/*.jpg ./
-
写博客时直接引用绝对链接
1
2... which is shown in the screenshot below: 
-
此步骤非绝对:作者写博客时在本地使用编辑器(本人为 Typora)需要在 yaml 说明头中添加
typora-root-url: ../../owenliu1122.github.io
例如:
1
2
3
4
5
6--- layout: post title: "并发和并行的区别 " Autor: "owenliu" typora-root-url: ../../owenliu1122.github.io ---
本地测试环境不支持中文文件名
刚刚接触 github pages,在 Mac 上安装了 Ruby,环境后,使用 jekyll 搭建博客时候,在本地预览时候无法打开,报以下错误信息:
1 |
|
或者
1 |
|
而提交到 github 上却可以正常解析。看了一下发现是文件写的博客有什么变化,原来是因为博客的 markdown文件使用了中文文件名,jekyll 无法正常解析,所以才出现乱码。
解决方案有两种:
-
修改 Ruby 的 lib 文件【转自】
/System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/lib/ruby/2.3.0/webrick/httpservlet/` 下的 filehandler.rb 文件,先备份.
找到下列两处,添加一句(
+
的一行为添加部分)1
path = req.path_info.dup.force_encoding(Encoding.find("filesystem"))+ path.force_encoding("UTF-8") # 加入编码if trailing_pathsep?(req.path_info)
1
break if base == "/"+ base.force_encoding("UTF-8") #加入編碼break unless File.directory?(File.expand_path(res.filename + base))
修改完重新
jekyll serve
即可支持中文文件名。
⚠️注意:这里修改库文件有可能失败,解决方案参考这里
-
基于 Docker 搭建本地 jykell 环境【转自】
在本地安装 Jekyll 虽然不是很复杂,但对于不懂 Ruby 的小白用户来说,安装 Ruby, RubyGems, GCC&Make 也不是很轻松,还好有 Docker,可以一键 Setup.
安装Docker
参考:Install Docker,docker compose
创建docker-compose.yml
1
2
3
4
5
6
7jekyll: image: jekyll/jekyll:pages command: jekyll serve --watch ports: - 3999:4000 volumes: - ~/dev/git/archerwq.github.io:/srv/jekyll/
-
jekyll/jekyll: pages 是专门适用于 Github Pages 的 Jekyll 镜像
-
jekyll serve –watch: 启动容器时运行的命令,这个命令会启动 Jekyll 内置的用于开发环境的 Web 服务器,**–watch **参数表示有任何文件变化时自动重新生成网页
-
3999:4000: 把容器的 4000 端口映射到宿主机的 3999 端口
-
xxxxx/owenliu1122.github.io:/srv/jekyll/ 把宿主机上的 Jekyll Site 所在目录映射到容器的/srv/jekyll/目录,Jekyll 默认从这个目录读 Jekyll Site
启动 Docker 容器
在 docker-compose.yml 所在目录运行 docker-compose up 命令, 如下:
1
2
3
4
5
6
7
8
9➜ github.io docker-compose -f docker-compose.yml up -d Pulling jekyll (jekyll/jekyll:pages)... pages: Pulling from jekyll/jekyll 6c40cc604d8e: Pull complete 4e0e4ac8c025: Pull complete 9a13ad0cfe1d: Pull complete 16f42435de28: Pull complete 6b537e0b3f4d: Pull complete Creating githubio_jekyll_1 ... done
这样你就可以在本地编辑文章,然后通过访问
http://localhost:3999
动态的看到文章的显示效果。 -
修改默认主题有两种方式
- 在_layouts目录添加自己的主题,还包括_includes/_sass/assets
- 修改Gemfile来加载现成的第三方主题,有点像CocoaPods
打开Gemfile
1 |
|
然后更新Gemfile配置
1 |
|
看一下我们都下载那些主题,这些主题和GitHub官网推荐的主题是一样的
1 |
|
我们只要修改_config.yml里面的主题字段就可以使用了 theme: jekyll-theme-minimal
另外还有很多现成的第三方主题,可以在https://rubygems.org/搜索”jekyll theme”看到
gem uninstall listen gem install listen bundle
Jekyll 中的配置和模板语法
配置
文件介绍
_config.yml
Jekyll 的全局配置文件。 比如网站的名字,网站的域名,网站的链接格式等等。
_drafts
未发布的 posts 存放的地方,这里的 post 文件名不需要加日期标记。
_includes
该目录下的文件内容是最终要放进模版文件中的一些代码片段。 对于网站的头部,底部,侧栏等公共部分,为了维护方便,我们可能想提取出来单独编写,然后使用的时候包含进去即可。 这时我们可以把那些公共部分放在这个目录下,使用时只需要引入即可。
1 |
|
_layouts
存放一些模版文件,模版是用来包含并装饰 page 或 post 内容的。Jekyll 的模版使用 HTML 语法来写,并包含 YAML Front Matter。 所有的模版都可用 Liquid 来与网站进行交互,都可以使用全局变量 site 和 page 。
site 变量: 包含该网站所有可以接触得到的内容和元数据(meta-data) page 变量: 包含的是当前渲染的page或post的所有可以接触得到的数据
对于网站的布局,一般会写成模板的形式,这样对于写实质性的内容时,比如文章,只需要专心写文章的内容,然后加个标签指定用哪个模板即可。 对于内容,指定模板了模板后,我们可以称内容是模板的儿子。 为什么这样说呢? 因为这个模板时可以多层嵌套的,内容实际上模板,只不过是叶子节点而已。
在模板中,引入儿子的内容:
1 |
|
在儿子中,指定父节点模板:
注意,必须在子节点的顶部。
1 |
|
_posts
发布的内容,比如博客文章,常放在这里面,而且一般作为叶子节点。
文件的命名必须遵循:YEAR-MONTH-DAY-title.markdown
。
另外,所有放在根目录下并且不以下划线开头的文件夹中有格式的文件都会被 Jekyll 处理成 page。 这里说的有格式是指含有 YAML Front Matter 头部的文件。
所有的 post 和 page 都要用 markdown 或者 texile 或者 HTML 语法来写,可以包含 Liquid 模版的语法。而且必须要有 YAML Front Matter 头部( Jekyll 只处理具有 YAML Front Matter 的文件)。
YAML Front Matter 必须放在文件的开头,一对---
之间,用户可在这一对---
间设置预先定义的变量或用户自己的数据。具体看下面的 说明。
_data
Jekyll 支持从该目录中加载 YAML、 JSON、 和 CSV 格式(.yml
、yaml
、json
或csv
扩展名)的文件数据。用于配置一些全局变量,不过数据比较多,所以放在这里。
比如,多人参与网站开发,我们通常会在这里面定义一个members.yml文件。
例如文件内容为:
1 |
|
然后在模板中我们就可以通过site.data.members
(注意:文件名决定变量名)使用这些数据。
1 |
|
_site
Jekyll 生成的网页默认输出的地方,一般需要在.gitignore
中屏蔽掉这个目录。
index.html
主页文件,后缀有时也用 index.md
等。
这个需要根据自己的需要来写,因为不同的格式之间在某些情况下还是有一些细微的差别的。
其他静态资源
对于其他静态资源,可以直接放在根目录或任何其他目录,然后路径和平常的网站一样,按路径来找链接中的文件。
配置全局变量
虽然全局变量都有自己的 默认配置,但是我们往往会手动配置为自己心中最好的效果。 另外,一些全局变量既可以在配置文件中设置,也可以在命令行选项参数里指定。
注意,配置不用使用 tab,否则可能会忽略那条命令。
源代码的位置
这个一般不配置,默认即可。
1 |
|
当然编译的时候也可以指定,但是使用 github 我们是不能指定参数的。
1 |
|
输出网站位置
这个一般也是默认。
1 |
|
Safe 开关
官方文档上就一句话:
1 |
|
大概意思是禁用常用的插件,忽略符号链接。
1 |
|
Base URL
将 Jekyll 生成的网站内容放置在域名的子路径下面。
我们经常需要在多个地方运行 Jekyll,如发布到 GitHub Pages 前在本地预览下网站。--baseurl
标记就是为此而生的。
首先在_config.yml
文件添加baseurl
,然后在网站各个链接的地方加前缀{{site.baseurl}}
。
当jekyll serve
预览本地网站时,在本地域名后追加--baseurl
的值(类似/
这样的路径)。
1 |
|
注意:所有的 page 和 post 的 URL 都是以斜线/
领头,那么当site.baseurl=/
时,连接的 URL 会出现两个重复的/
而破坏超链接。因此,建议只在baseurl
有具体值时才使用site.baseurl
给 URL 加前缀。
忽略文件
这个很有用,有时候你写了一个文件,里面的一个东西可能会被 Jekyll 处理,但是你不想让 Jekyll 处理的话,就使用这个语法忽略那些文件。
1 |
|
强制处理文件
有时候我们的一些文件的名字由于不在 Jekyll 处理的文件名字范围内,这时候就需要强制处理这些文件了。比如.htaccess
文件。
1 |
|
时区
模板中经常会对时间进行转换,这个时候如果至指定时区的话,可能得到的时间会和我们想要的时间错几个小时。在 这里 能查看到可用的值。
1 |
|
编码
大家都是程序员,就不用多说了。
执行ruby-e'puts Encoding::list.join("\n")'
可列出本地 Ruby 可用的编码。
1 |
|
文章链接格式
我们可以自定义 Post 的 URL 格式,通过 permalink
来配置。比如:
1 |
|
另外,还有3种内置的链接格式可以使用:
PERMALINK STYLE | URL TEMPLATE |
---|---|
date | /:categories/:year/:month/:day/:title.html |
pretty | /:categories/:year/:month/:day/:title/ |
none | /:categories/:title.html |
分页
通常我们都不想把所有的 Post 都放在一页显示,而是要分成多页显示。好在 Jekyll 支持分页显示,通过paginate
和paginate_path
两个变量来设置每页显示的数量和分页 HTML 的 URL 路径。
1 |
|
根据上面的配置,Jekyll 会读取blog/index.html
文件,把每页赋值给全局变量paginator
,并输出 HTML 分页文件,如:第2页为blog/page2/index.html
。其中,“page” 是字符常量,变量:num
是分页的页码,自动从 2 开始编码,因此在罗列所有页面页码及它们的超链接时要注意一下,首页链接没有中间的 “page1” 路径。
通过paginator
的相关属性我们可以实现在不同页间切换。
1 |
|
默认值设定
设置 YAML Front Matter 变量的默认值。
写 post 时,经常需要在每篇文章的 YAML 头部设定一些相同的变量使用,比如:author
、layout
等。为了避免这些不必要的重复性操作,我们可以在配置文件中设定他们的默认值;
同时在必要的时候,还可以对具体文件设定头部变量,覆盖其默认值。下面很快就会说这点。
1 |
|
Jekyll 模板、变量
Jekyll 模板实际上分两部分:一部分是头部定义,另一部分是Liquid 语法。
头部定义
主要用于指定模板(layout)和定义一些变量,比如:标题(title)、描述(description)、标签(tags)、分类(category/categories)、是否发布(published),以及其他自定义的变量。
1 |
|
注意:如果文本文件使用的是utf-8
编码,那么必须确保文件中不存在BOM
头部字符,尤其是当 Jekyll 运行在 Windows 平台上。
使用变量
关于 Jekyll 的变量,可以参考官方说明 上面文章页面中定义的头部变量,需要使用下面的语法获得:
1 |
|
这些自定义的变量将会被传递给 Liquid 模板引擎用于转换文本文件,例如,你可以用上面定义的 “title” 变量在 layout 中设置页面的标题:
1 |
|
所有的变量都是一个树节点,比如:page 就是当前页面的根节点。
其中全局根结点有:
- site:
_config.yml
中配置的信息 - page: 页面的配置信息,包括 YAML 中定义的变量
- content: 用在模板文件中,该变量包含页面的子视图,用于引入子节点的内容;不能在 post 和 page 文件中使用
- paginator: 分页信息,需要事先设定 site 中的
paginate
值,参考Pagination
注意:post
变量仅作用于for
循环内部,如 {%forpostinsite.posts%}
。假如需要访问当前正在渲染的文章页面的变量,就要用page
变量代替 post 对象。比如,post 的 title 变量,要通过page.title
来访问。
site 下的变量
变量 | 描述 |
---|---|
site.time | 当前的时间(运行 Jekyll 时的时间) |
site.pages | 所有页面列表 |
site.posts | 按时间逆序排列的所有文章列表 |
site.related_posts | 如果当前被处理的页面是一个 post 文件,那这个变量是一个包含了最多10篇相关的文章列表 |
site.static_files | 所有静态文件的列表(如:没有被 Jekyll 处理的文件),每个文件有3个属性:path 、modified_time 和extname |
site.html_pages | 所有 HTML 页面列表 |
site.collections | 自定义的对象集合列表,参考Collections |
site.data | _data 目录下 YAML 文件的数据列表 |
site.documents | 所有 Collections 里面的文档列表 |
site.categories.CATEGORY | 所有在 CATEGORY 类别下的 post 列表 |
site.tags.TAG | 所有在 TAG 标签下的 post 列表 |
site.[CONFIGURATION_DATA] | 其他自定义的变量 |
page 下的变量
变量 | 描述 |
---|---|
page.content | 页面的内容 |
page.title | 页面的标题 |
page.excerpt | 未渲染的摘要 |
page.url | 不带域名的页面链接,如:/2008/12/14/my-post.html |
page.date | 指定每一篇 post 的时间,可在 post 的 front matter 里覆盖这个值,格式是:date:YYYY-MM-DD HH:MM:SS |
page.id | 每一篇 post 的唯一标示符(在RSS中非常有用),如:/2008/12/14/my-post |
page.categories | post 隶属的一个分类列表,可在 YAML 头部指定 |
page.tags | post 隶属的一个标签列表,可在 YAML 头部指定 |
page.path | 页面的源码地址 |
page.next | 按时间顺序排列的下一篇文章 |
page.previous | 按时间顺序排列的上一篇文章 |
paginator 下的变量
分页只在 index 页面中有效,index 页面可以在子目录里,比如:主页在/blog/index.html
,那么通过配置paginate_path:"blog/page:num/"
,主页里面放不下的其他内容就可以设定在第 2 页blog/page2/index.html
以及后面的页面中。
变量 | 描述 |
---|---|
paginator.per_page | 每一页的 post 数量 |
paginator.posts | 当前页面上可用的 post 列表 |
paginator.total_posts | 所有 post 的数量 |
paginator.total_pages | 分页总数 |
paginator.page | 当前页的页码,或者nil |
paginator.previous_page | 上一页的页码,或者nil |
paginator.previous_page_path | 上一页的路径,或者nil |
paginator.next_page | 下一页的页码,或者nil |
paginator.next_page_path | 下一页的路径,或者nil |
Liquid 语法
Liquid是 Ruby 的一个模版引擎库,Jekyll中用到的Liquid标记有两种:输出和标签。
- Output 标记:变成文本输出,被2层成对的花括号包住,如:
{{content}}
- Tag 标记:执行命令,被成对的花括号和百分号包住,如:
{%command%}
Jekyll 输出 Output
示例:
1 |
|
Output 标记可以使用过滤器 Filters 对输出内容作简单处理。 多个 Filters 间用竖线隔开,从左到右依次执行,Filter 左边总是输入,返回值为下一个 Filter 的输入或最终结果。
1 |
|
标准过滤器 Filters
下面是常用的过滤器方法,更多的API需要查阅源代码(有注释)才能看到。
源码主要看两个 Ruby Plugin 文件:filters.rb
(Jekyll) 和standardfilters.rb
(Liquid)。
(这也是博主刚开始使用Jekyll的时候,比较头疼的问题。由于官方没有给出详细API的说明,只能去源代码那里看啦,好在代码的注释比较详细)
date
- 将时间戳转化为另一种格式 (syntax reference)capitalize
- 输入字符串首字母大写 e.g.{{'capitalize me'|capitalize}}# => 'Capitalize me'
downcase
- 输入字符串转换为小写upcase
- 输入字符串转换为大写first
- 返回数组中第一个元素last
- 返回数组数组中最后一个元素join
- 用特定的字符将数组连接成字符串输出sort
- 对数组元素排序map
- 输入数组元素的一个属性作为参数,将每个元素的属性值映射为字符串size
- 返回数组或字符串的长度 e.g.{{array|size}}
escape
- 将字符串转义输出 e.g.{{"test"|escape}}# => test
escape_once
- 返回转义后的HTML文本,不影响已经转义的HTML实体strip_html
- 删除 HTML 标签strip_newlines
- 删除字符串中的换行符(\n
)newline_to_br
- 用HTML\n
replace
- 替换字符串中的指定内容 e.g.{{'foofoo'|replace:'foo','bar'}}# => 'barbar'
replace_first
- 查找并替换字符串中第一处找到的目标子串 e.g.{{'barbar'|replace_first:'bar','foo'}}# => 'foobar'
remove
- 删除字符串中的指定内容 e.g.{{'foobarfoobar'|remove:'foo'}}# => 'barbar'
remove_first
- 查找并删除字符串中第一处找到的目标子串 e.g.{{'barbar'|remove_first:'bar'}}# => 'bar'
truncate
- 截取指定长度的字符串,第2个参数追加到字符串的尾部 e.g.{{'foobarfoobar'|truncate:5,'.'}}# => 'foob.'
truncatewords
- 截取指定单词数量的字符串prepend
- 在字符串前面添加字符串 e.g.{{'bar'|prepend:'foo'}}# => 'foobar'
append
- 在字符串后面追加字符串 e.g.{{'foo'|append:'bar'}}# => 'foobar'
slice
- 返回字符子串指定位置开始、指定长度的子串 e.g.{{"hello"|slice:-4,3}}# => ell
minus
- 减法运算 e.g.{{4|minus:2}}# => 2
plus
- 加法运算 e.g.{{'1'|plus:'1'}}#=> '11', {{ 1 | plus:1 }} # => 2
times
- 乘法运算 e.g{{5|times:4}}# => 20
divided_by
- 除法运算 e.g.{{10|divided_by:2}}# => 5
split
- 根据匹配的表达式将字符串切成数组 e.g.{{"a~b"|split:"~"}}# => ['a','b']
modulo
- 求模运算 e.g.{{7|modulo:4}}# => 3
Jekyll 标签 Tag
标签用于模板中的执行语句。目前 Jekyll/Liquid 支持的标准标签库有:
Tags | 说明 |
---|---|
assign | 为变量赋值 |
capture | 用捕获到的文本为变量赋值 |
case | 条件分支语句 case…when… |
comment | 注释语句 |
cycle | 通常用于在某些特定值间循环选择,如颜色、DOM类 |
for | 循环语句 |
if | if/else 语句 |
include | 将另一个模板包进来,模板文件在_includes 目录中 |
raw | 禁用范围内的 Tag 命令,避免语法冲突 |
unless | if 语句的否定语句 |
1. Comments
仅起到注释 Liquid 代码的作用。
1 |
|
2. Raw
临时禁止执行 Jekyll Tag 命令,在生成的内容里存在冲突的语法片段的情况下很有用。
1 |
|
3. If / Else
条件语句,可以使用关键字有:if
、unless
、elsif
、else
。
1 |
|
3. If / Else
条件语句,可以使用关键字有:if
、unless
、elsif
、else
。
1 |
|
4. Case 语句
适用于当条件实例很多的情况。
1 |
|
5. Cycle
经常需要在相似的任务间选择时,可以使用cycle
标签。
1 |
|
如果要对循环作分组处理,可以指定分组的名字:
1 |
|
6. For loops
循环遍历数组:
1 |
|
循环迭代 Hash散列,item[0]
是键,item[1]
是值:
1 |
|
每个循环周期,提供下面几个可用的变量:
1 |
|
还有几个属性用来限定循环过程:
limit:int
: 限制循环迭代次数
offset:int
: 从第n个item开始迭代
reversed
: 反转循环顺序
1 |
|
允许自定义循环迭代次数,迭代次数可以用常数或者变量说明:
1 |
|
7. Variable Assignment
为变量赋值,用于输出或者其他 Tag:
1 |
|
capture
允许将大量字符串合并为单个字符串并赋值给变量,而不会输出显示。
1 |
|
其他模板语句
字符转义
有时候想输出{
了,怎么办? 使用反斜线\
转义即可
1 |
|
格式化时间
1 |
|
代码语法高亮
安装好pygments.rb的 gem 组件和 Python 2.x 后,配置文件添加:highlighter:pygments
,就可以使用语法高亮命令了,支持语言多达 100 种以上。
1 |
|
上面的示例中,使用highlight
语句来处理代码块;并设定第一个参数ruby
来指定高亮的语言 Ruby,第二个参数linenos
来开启显示代码行号的功能。
为了给代码着色,需要配置相应的样式文件,参考syntax.css;
为了更好的显示行号,可以在上面的 CSS 文件添加.lineno
样式类。
可用的语言识别符缩写,从Pygments’ Lexers Page查阅。 如果从 Pygments 的Supported Languages清單,能發現明明有列出該語言名稱,而 pygments.rb 确无法识别该语言,這時候必須到Available Lexers查詢;如果在程序語言的說明中有一行“New in version 1.5.”,那就表示只要將Pygments更新到 1.5 版, 即可支持该程序语言。
链接同域内的 post
使用post_url
Tag 可以自动生成网站内的某个 post 超链接。
这个命令语句以相关 post 的文件名为参数,在引入同域的 post 链接时,非常有用。
1 |
|
Gist 命令
嵌入 GitHub Gist,也可以指定要显示的 gist 的文件名。
1 |
|
生成摘要
配置文件中设定excerpt_separator
取值,每篇 post 都会自动截取从开始到这个值间的内容作为这篇文章的摘要post.excerpt
使用。
如果要禁用某篇文章的摘要,可以在该篇文章的 YAML 头部设定excerpt_separator:""
。
1 |
|
删除 HTML 标签
这个在摘要作为head
标签里的meta="description"
内容输出时很有用
1 |
|
删除指定文本
过滤器remove
可以删除变量中的指定内容
1 |
|
CGI Escape
通常用于将 URL 中的特殊字符转义为%xx
形式
1 |
|
排序
1 |
|
搜索指定 Key
1 |
|
To JSON 格式
将 Hash 散列或数组转换为 JSON 格式
1 |
|
序列化
把一个数组变成一个字符串
1 |
|
单词的个数
1 |
|
内容名字规范
对于博客 post,文件命名规则必须是YEAR-MONTH-DAY-title.MARKUP
的格式。
使用rake post
会自动将 post 文件合适命名。
比如:
1 |
|
Assets 样式文件
Jekyll 支持 Sass 和 CoffeeScript,通过新建.sass
、.scss
或.coffee
格式的文件,并在开头添加一对---
来使用这个功能。
关于详细的使用,请参看官方说明,这里就不再做介绍了。