基于mkdocs-material实现的帮助中心(markdown + 中文搜索 + 图片放大)

代码幽篁使
• 阅读 12725

需求

  • 整站文档使用markdown,方便产品&运营童鞋们编写
  • 支持搜索
  • 点击图片能放大

最终完成效果如下:
基于mkdocs-material实现的帮助中心(markdown + 中文搜索 + 图片放大)
左侧导航栏支持多层级嵌套,右侧为当前文档内标题导航。

顶部右侧搜索栏(目前只支持分词搜索,不支持整句):
基于mkdocs-material实现的帮助中心(markdown + 中文搜索 + 图片放大)

图片放大:
基于mkdocs-material实现的帮助中心(markdown + 中文搜索 + 图片放大)

实现

mkdocs-demo.git

更全面的信息请移步官网:
mkdocs官网
mkdocs-material官网

环境搭建

python: 3.7.2

# 安装依赖
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.6

目录说明&基础配置

项目目录如下:
基于mkdocs-material实现的帮助中心(markdown + 中文搜索 + 图片放大)

  • assets:自定义资源

    • css
    • js
    • syntax:语法示例(可忽略)
  • img:存储文档内图片资源
  • label:文档内容
  • index.md:首页

mkdocs.yml配置

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文件,包含锚点位置、标题、描述及标题与描述对应的分词库。大概长这样:
    基于mkdocs-material实现的帮助中心(markdown + 中文搜索 + 图片放大)
  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}

搞定~

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
3年前
java反射, 不看你可别后悔
<divid"content\_views"class"markdown\_views"<!flowchart箭头图标勿删<svgxmlns"http://www.w3.org/2000/svg"style"display:none;"<pathstrokelinecap"round"d"M5,00,
Stella981 Stella981
3年前
AndroidStudio封装SDK的那些事
<divclass"markdown\_views"<!flowchart箭头图标勿删<svgxmlns"http://www.w3.org/2000/svg"style"display:none;"<pathstrokelinecap"round"d"M5,00,2.55,5z"id"raphael
Easter79 Easter79
3年前
Taro小程序自定义顶部导航栏
微信自带的顶部导航栏是无法支持自定义icon和增加元素的,在开发小程序的时候自带的根本满足不了需求,分享一个封装好的组件,支持自定义icon、扩展dom,适配安卓、ios、h5,全面屏。我用的是京东的Taro多端编译框架写的小程序,原生的也可以适用,用到的微信/taro的api做调整就行,实现效果如下。!在这里插入图片描述(https://i
Stella981 Stella981
3年前
Native memory allocation (mmap) failed to map xxx bytes for committing reserved memory
<divid"content\_views"class"markdown\_views"<!flowchart箭头图标勿删<svgxmlns"http://www.w3.org/2000/svg"style"display:none;"<pathstrokelinecap"round"d"M5,00,
Stella981 Stella981
3年前
Spring Boot 2下使用Feign找不到@EnableFeignClients的解决办法
<divid"content\_views"class"markdown\_views"<!flowchart箭头图标勿删<svgxmlns"http://www.w3.org/2000/svg"style"display:none;"<pathstrokelinecap"round"d"M5,00,2
Wesley13 Wesley13
3年前
Java8中的LocalDateTime工具类
<divid"content\_views"class"markdown\_views"<!flowchart箭头图标勿删<svgxmlns"http://www.w3.org/2000/svg"style"display:none;"<pathstrokelinecap"round"d"M5,00,
Stella981 Stella981
3年前
Markdown编辑器Haroopad配置
我的配置预览效果,图片过大,可下载后放大查看!输入图片说明(https://static.oschina.net/uploads/img/201610/27211728_gy21.png"在这里输入图片标题")是一款跨平台的markdown编辑器,界面美观,可支持数学表达式,并提供目录支持,自带多套
Wesley13 Wesley13
3年前
mysql查询每个学生的各科成绩,以及总分和平均分
今天看一个mysql教程,看到一个例子,感觉里面的解决方案不是很合理。问题如下:有学生表:!在这里插入图片描述(https://oscimg.oschina.net/oscnet/07b001b0c6cb7e0038a9299e768fc00a0d3.png)成绩表:!在这里插入图片描述(https://oscimg.o