基於mkdocs-material實現的幫助中心(markdown + 中文搜索 + 圖片放大)

需求

  • 整站文檔使用markdown,方便產品&運營童鞋們編寫
  • 支持搜索
  • 點擊圖片能放大

最終完成效果以下:
圖片描述
左側導航欄支持多層級嵌套,右側爲當前文檔內標題導航。javascript

頂部右側搜索欄(目前只支持分詞搜索,不支持整句):
搜索區域css

圖片放大:
圖片描述java

實現

更全面的信息請移步官網:
mkdocs官網
mkdocs-material官網node

環境搭建

python: 3.7.2python

# 安裝依賴
pip install mkdocs mkdocs-material
pip install jieba
# 本地調試
mkdocs serve
# 打包
mkdocs build
包名 模塊名 版本
mkdocs mkdocs 1.0.4
mkdocs-material material 3.0.6
Markdown markdown 3.0.1
pymdown-extensions pymdownx 6.0
jieba jieba 0.39

筆者使用mkdocs-material 4.0.1時遇着大坑,建議制定版本安裝3.0.6jquery

目錄說明&基礎配置

項目目錄以下:
圖片描述git

  • assets:自定義資源github

    • css
    • js
    • syntax:語法示例(可忽略)
  • img:存儲文檔內圖片資源
  • label:文檔內容
  • index.md:首頁

mkdocs.yml配置web

site_name: '幫助中心'
site_author: zzm
site_url: http://xxx.com/help/
# 靜態資源輸出文件夾
site_dir: ../dist/help

# 左側導航
nav:
- 介紹: index.md
- 標籤服務系統幫助文檔:
  - 標籤平臺用戶手冊: label/user_manual.md
  - 標籤數聽說明文檔: label/data_desc.md
  - 標籤需求對接流程: label/demand_process.md
- 統一標籤API服務:
  - 0.常見問題:

# 本地調試端口
dev_addr: 127.0.0.1:4050
# 主題配色
theme:
  name: material
  language: 'zh'
  favicon: 'assets/favicon.ico'
  logo:
    icon: ' '
  palette:
    primary: 'Light Blue'
    accent: 'Light Blue'
  feature:
    tabs: false
# 自定義css
extra_css:
- 'assets/css/custom.css'
- 'assets/css/simpleLightbox.min.css'
# 自定義js
extra_javascript:
- 'assets/js/jquery-3.2.1.min.js'
- 'assets/js/simpleLightbox.min.js'
- 'assets/js/custom.js'
# 一些擴展
markdown_extensions:
- markdown.extensions.attr_list
- admonition
- codehilite:
    guess_lang: false
    linenums: false
- toc:
    permalink: true
- footnotes
- meta
- def_list
- pymdownx.arithmatex
- pymdownx.betterem:
    smart_enable: all
- pymdownx.caret
- pymdownx.critic
- pymdownx.details
- pymdownx.inlinehilite
- pymdownx.magiclink
- pymdownx.mark
- pymdownx.smartsymbols
- pymdownx.superfences
- pymdownx.tasklist
- pymdownx.tilde

添加中文搜索支持

目前網上找到的教程都是針對lunr源碼替換,但不少都是歷史版本的解決方案,隨着lunr的更新,不少API已經面目全非,文件夾啥的都對不上,比較懵圈。這裏會提供稍微新一點的方案。固然,最終解決方案仍是要改造下lunr。算法

lunr的工做原理能夠歸納爲兩步:

  1. 提取頁面純文字版內容到一個json文件,包含錨點位置、標題、描述及標題與描述對應的分詞庫。大概長這樣:
    lunr生成json
  2. 把搜索框輸入的內容根據分隔符(空格、標點符號等)切成分詞,並和第1步的分詞庫進行比對,根據對應錨點尋址頁面。

實現中文搜索困難的地方在於中文分詞的機制和英文不一樣,不能簡單使用分隔符去切詞,而中文分詞的算法複雜,將全部頁面信息臨時構建成分詞庫的效率就會很低。

英文版的lunr如今已經支持日文,對於「幫助文檔簡介」,能夠獲得三個分詞:幫助,文檔,簡介。這種機制是,lunr分詞是由分隔符導向,同時對詞長有必定限制,相似這種漢字過多的成句,只能保留每段分割的前兩個字。因此在搜索的時候,成句(通常是大於倆字)目前是搜索不到的,但能夠經過空格切割成句進行搜索。

改動以下:

  • 進入python的安裝目錄修改search_index.py文件

    個人目錄在/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/mkdocs/contrib/search/,修改generate_search_index

def generate_search_index(self):
        """python to json conversion"""
        page_dicts = {
            'docs': self._entries,
            'config': self.config
        }
        for doc in page_dicts['docs']: # 調用jieba的cut接口生成分詞庫,過濾重複詞,過濾空格
            tokens = list(set([token.lower() for token in jieba.cut_for_search(doc['title'].replace('\n', ''), True)]))
            if '' in tokens:
                tokens.remove('')
            doc['title_tokens'] = tokens

            tokens = list(set([token.lower() for token in jieba.cut_for_search(doc['text'].replace('\n', ''), True)]))
            if '' in tokens:
                tokens.remove('')
            doc['text_tokens'] = tokens

        data = json.dumps(page_dicts, sort_keys=True, separators=(',', ':'), ensure_ascii=False)

        if self.config['prebuild_index']:
            try:
                script_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'prebuild-index.js')
                p = subprocess.Popen(
                    ['node', script_path],
                    stdin=subprocess.PIPE,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE
                )
                idx, err = p.communicate(data.encode('utf-8'))
                if not err:
                    idx = idx.decode('utf-8') if hasattr(idx, 'decode') else idx
                    page_dicts['index'] = json.loads(idx)
                    data = json.dumps(page_dicts, sort_keys=True, separators=(',', ':'), ensure_ascii=False)
                    log.debug('Pre-built search index created successfully.')
                else:
                    log.warning('Failed to pre-build search index. Error: {}'.format(err))
            except (OSError, IOError, ValueError) as e:
                log.warning('Failed to pre-build search index. Error: {}'.format(e))

        return data
  • 修改lunr.js

    個人目錄:/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/mkdocs/contrib/search/templates/search/,搜索lunr.Builder.prototype.add替換部分代碼

// 僅替換前15行
lunr.Builder.prototype.add = function (doc, attributes) {
  var docRef = doc[this._ref],
      fields = Object.keys(this._fields)

  this._documents[docRef] = attributes || {}
  this.documentCount += 1

  for (var i = 0; i < fields.length; i++) {
    var fieldName = fields[i],
        extractor = this._fields[fieldName].extractor,
        field = extractor ? extractor(doc) : doc[fieldName],
        tokens = doc[fieldName + '_tokens'],
        terms = this.pipeline.run(tokens),
        fieldRef = new lunr.FieldRef (docRef, fieldName),
        fieldTerms = Object.create(null)

還有一部分需替換

lunr.trimmer = function (token) {
  return token.update(function (s) {
    return s.replace(/^\s+/, '').replace(/\s+$/, '')
  })
}

搞定~ 如今輸入中文搜索不到的問題就解決啦

點擊圖片放大

圖片放大又稱Lightbox,主要是提供一個浮窗,以展現頁面上縮略圖的大圖版。另外一類叫zoom-in,主要是實現鼠標懸停時出現放大鏡。目前在markdown中要使用只都能經過外部引入。

首先 下載css及js並引入: Simple lightbox

|---assets
|   |---css
|   |   |----simpleLightbox.min.css
|   |   `----custom.css
|   `---js
|       |----simpleLightbox.min.js
|       `----custom.js

下一步,在配置文件mkdocs.yml中設置extra_css與extra_javascript(如前文配置);
下一步,在custom.css和custom.js中分別添加:

/* custom.css */
a.boxedThumb {
  display: block;
  padding: 4px;
  line-height: 20px;
  border: 1px solid #ddd;
  -webkit-border-radius: 4px;
  -moz-border-radius: 4px;
  border-radius: 4px;
  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);
  -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);
  -webkit-transition: -webkit-transform .15s ease;
  -moz-transition: -moz-transform .15s ease;
  -o-transition: -o-transform .15s ease;
  -ms-transition: -ms-transform .15s ease;
  transition: transform .15s ease;
}

a.boxedThumb:hover {
  -webkit-transform: scale(1.05);
  -moz-transform: scale(1.05);
  -o-transform: scale(1.05);
  -ms-transform: scale(1.05);
  transform: scale(1.05);
  z-index: 5;
}
$(document).ready(function () {
  let productImageGroups = []
  $('.img-fluid').each(function () {
    let productImageSource = $(this).attr('src')
    let productImageTag = $(this).attr('tag')
    let productImageTitle = $(this).attr('title')
    if (productImageTitle) {
      productImageTitle = 'title="' + productImageTitle + '" '
    }
    else {
      productImageTitle = ''
    }
    $(this).
        wrap('<a class="boxedThumb ' + productImageTag + '" ' +
            productImageTitle + 'href="' + productImageSource + '"></a>')
    productImageGroups.push('.' + productImageTag)
  })
  jQuery.unique(productImageGroups)
  productImageGroups.forEach(productImageGroupsSet)

  function productImageGroupsSet (value) {
    $(value).simpleLightbox()
  }
})

注:此處要確保下述插件開啓,它容許在MarkDown連接/圖片後用括號指明任意標籤的字段。

markdown_extensions:
  - markdown.extensions.attr_list

使用時

![流程圖](./../img/user_manual_1.png){.img-fluid tag=1}
# 帶說明描述
![流程圖](./../img/user_manual_1.png){.img-fluid tag=2 title="測試說明"}
# 圖片組
![流程圖](./../img/user_manual_1.png){.img-fluid tag=3}
![流程圖](./../img/user_manual_1.png){.img-fluid tag=3}
![流程圖](./../img/user_manual_1.png){.img-fluid tag=3}

搞定~

相關文章
相關標籤/搜索