Filter 插件是什麼?#
Filters 插件是 Jekyll 插件中最為常見的一種類型,它可以將一種 Ruby 的內部方法暴露給 Liquid ,最後在頁面呼叫。比如說,如果有閱讀使用 Jekyll 搭建的靜態網頁的話,我們可能會注意到很多形如下面的內容:
{% assign foo = 10 %}
{% foo | plus: 4 %}
{{ foo }}
這就是 Liquid 語言,第一行和第二行使用 {% %}
包著的是運算式,而第三行使用 {{ }}
包著的表示將抱著的變數輸出。Liquid 是一種很簡單的模板語言,半天就可以學完,對 Liquid 有更多興趣的可以去這個網站查看一下官方的文檔。
所以說了這麼多,Filter 到底是什麼呢?其實在上面的代碼中的第二行,plus
就是一個 Filter,表示把 foo
作為輸入,把 foo
加 4 後重新賦值給 foo
,相當於 foo = foo + 4
。
Filter 有什麼用?#
Filter 實際上或許是 Jekyll 所允許的插件中第二有用的插件類型(第一有用的插件類型應該是 Hook),其受用面非常廣,包括但不限於:
- 快捷計算兩個日期之間的差距。
- 對文章生成目錄。
- 自動混淆郵件地址。
- 計算文章字數和閱讀時間。
為什麼我覺得這些都可以用 JS 實現?#
確實,理論上來說所有使用 Filter 插件可以做到的事情都可以使用 javascript
在運行時完成,但如果我們使用插件來使這些事情在編譯時就完成了的話,無疑可以增強網站在遊覽器上的性能,所以還是非常有用的。
注意!Pages 上無法使用插件#
GitHub Pages (或者其他大部分 Pages) 考慮到安全因素,都通過 —safe 選項禁用了插件功能。因此如果你的網站部署在 Github Pages ,那麼你的插件不會工作。
不過仍然有辦法發布到 GitHub Pages,你只需在本地做一些轉換,並把生成好的文件上傳到 Github 替代 Jekyll 就可以了。
讓我們開始吧#
本篇將從最簡單的 Filter 開始,實現一個簡單的計算文章字數和閱讀時間的 Filter。這個 Filter 可以幫助網頁在展示文章的同時展示字數和預計的閱讀時間。
根據 Jekyll 的官方文檔,所有的 Jekyll 插件都要存儲在項目目錄下的 _plugins
文件夾,所以如果項目根目錄下沒有 _plugins
文件夾的話需要先手動新建一個 _plugins
文件夾。然後我們在新建的 _plugins
文件夾中新建一個 Ruby 文件叫做 jekyll_reading_time.rb
。然後打開這個文件,我們將我們的這個插件命名為 ReadingTime
。
module ReadingTime
end
我們需要暴露給 Liquid 的方法有兩個。第一個是 count_words(html)
方法:傳入網頁,計算文章中的字數;第二個是 reading_time(html)
方法:傳入網頁,計算大概的閱讀時間。reading_time(html)
方法很好寫,我們只需要得到有多少字數,然後除以每分鐘的閱讀字數,向上取整就是閱讀時間了。
module ReadingTime
def count_words(html)
end
def reading_time(html)
(count_words(html) / 140.0).ceil
end
end
為了計算網頁的字數,我們可以首先使用 Ruby 庫 nokogiri
來解析 html 為一個對象,然後遞歸每一個 html 對象,忽略一些肯定沒有文字的對象,對其他的對象查詢其中有沒有文字。我們使用私有函數來處理這個過程。
require ‘nokogiri’
module ReadingTime
def count_words(html)
words(html)
end
def reading_time(html)
(count_words(html) / 140.0).ceil
end
private
def text_nodes(root)
ignored_tags = %w[ area audio canvas code embed footer form img map math nav object pre script svg table track video ]
texts = 0
root.children.each { |node|
if node.text?
text_array = node.text.unpack(“U*”)
text_array.each { |c|
texts = texts + 1
}
elsif not ignored_tags.include? node.name
texts = texts + text_nodes(node)
end
}
texts
end
def words(html)
fragment = Nokogiri::HTML.fragment html
text_nodes(fragment)
end
end
可以看到我們的插件整體已經成型了,只差最後一步了,就是去 Jekyll 註冊這個插件。
為了向 Jekyll 註冊我們的新插件,我們只需要在模塊外調用 Jekyll 的註冊方法。
require ‘nokogiri’
module ReadingTime
def count_words(html)
words(html)
end
def reading_time(html)
(count_words(html) / 140.0).ceil
end
private
def text_nodes(root)
ignored_tags = %w[ area audio canvas code embed footer form img map math nav object pre script svg table track video ]
texts = 0
root.children.each { |node|
if node.text?
text_array = node.text.unpack(“U*”)
text_array.each { |c|
texts = texts + 1
}
elsif not ignored_tags.include? node.name
texts = texts + text_nodes(node)
end
}
texts
end
def words(html)
fragment = Nokogiri::HTML.fragment html
text_nodes(fragment)
end
end
Liquid::Template.register_filter(ReadingTime)
完成了!我們的第一個插件就這樣完成了!以後在編寫網頁的時候,如果想得到一篇文章的字數和估計的閱讀時間,只需要在 html 代碼中這樣寫就可以了:
這篇文章有 {{ post.content | count_words }} 字
大概需要 {{ post.content | reading_time }} 分鐘的閱讀