7

工作后一直在从事PHP开发, 从以前的大包大揽到现在的退居服务端写接口, 当中接触过几个的接口文档管理工具或系统, 简单描述下:

  1. showdoc, 功能全面而且简洁, 有用户,权限管理功能, 支持markdown, 支持导出word, 有多种文档模板, 目录支持两级折叠
  2. confluence, 功能强大(权限管理, 邮件提醒, 全文搜索, 插件管理等), 重, 收费的一个文档管理系统
  3. swagger, 需要在代码中写大量的注释去配合
  4. readmine, 功能丰富类似confluence, 它的文档是以txt保存的, 可以追溯变更, 可以全文搜索, 但是写文档有点痛苦, 适合任务/bug跟踪管理等
  5. gitbook, nodejs安装, 支持markdown, 支持npm插件, 左侧的可折叠的目录树就需要装插件, 也可以装搜索插件, 目录是单独的markdown文件, 我使用的时候感觉从md到HTML编译太慢(600+的文档, 要编译25分钟多, 如果有增量编译或提高编译速度的插件还请各位赐教)

两个月前因为项目的原因需要一个简单的工具来管理接口文档, 这次就把开发过程中的经历记录在这里, 抛砖引玉~

主要目标

  1. 可以多人编辑
  2. 可以在浏览器中查看
  3. 有一个可以自动展开并高亮的目录
  4. 支持多级目录
  5. 支持markdown
  6. 快, 方便

解决方法

  1. 结合git就可以实现, 正好也可以利用git的权限管理功能
  2. 需要将markdown编译成HTML文件部署到内网
  3. 因为要在浏览器中查看, 这里最终选择了接入简单, 界面清爽, 无依赖的dtree.js (不依赖jQuery), 改为了用PHP生成左侧目录树, 并优化css使之支持PC和手机端显示
  4. 这个功能用了树的后根序遍历算法实现了对多级文件的读取(没有用递归, 担心写着写着把自己绕进去), 正好dtree.js 也支持多级目录折叠
  5. 这里我选择了segmentfault官方出的PHP编译工具类,改用 parsedown (相较sf的类他没有安全校验, 支持单行内多个换行符)
  6. 快: 编译600多个文件, PHP用时1s左右,可以接受, 而且支持增量编译; 方便: 主要体现在目录是自动生成的, 不需要单独编写目录文件

其中遇到的问题:

增量编译

~~刚开始判断一个md文件是否需要编译成HTML, 是拿md文件的创建时间和最后修改时间做对比进行判断的,
但是后来发现, 一些复制来的, 重命名的文件用这个方法就不起作用.
最后使用了一个中间文件, 去记录本次编译的文件的时间, 再跟 max(创建时间, 最后修改时间)对比判断是否需要编译~~
2021年2月2日 更新:
因为文件的复制移动, 剪切移动, 重命名等情况会导致时间判断不准确, 而且时间的判断也不便于多人合作, 因此改为用md5摘要判断内容是否发生变化

删除多余文件

后续使用过程中发现, 有些md文档被删除了, 但是没有自动删除最终编译后的html文件,
因此, 在编译时会对md文件和最后的HTML文件求一个差集, 删掉那些多余的HTML文件

支持多级目录

开始的时候想着, 按照多级数组来设计保存文件的层级关系, 然后再根据这个数组来展示目录, 后来实现的时候觉得太麻烦, 实现不了多层级目录.
~~后来换了一种思路, 其实不同层级的文件, 显示的时候, 只是缩进不同而已: 文件名的缩进要比目录名的缩进大一些, 下级目录要比上级目录的缩进大一些;
于是:
首先通过树的遍历算法, 把文件夹中的所有文件的路径读出到一维数组中;
然后遍历每个文件路径, 将目录名和文件名拆开, 去重后, 都用p标签显示, 根据不同的层级, 增减p标签的padding-left, 达到缩进的效果;~~
2020年8月23日 更新
原来的想法在交互时,虽然生成的HTML结构很简单,但展开与隐藏实现起来太过复杂,就放弃了;
现在引入了一个php-html类,先通过树的遍历算法把源文件夹中的文档都读取出来, 然后用此类生成嵌套的HTML去展示菜单

目录的折叠与展开效果

~~如果p标签中存放的是目录名, 就用属性data-path记录当前路径的hash值(MD5(a/b/c/)),
如果p标签中存放的是文件名, 就将上层目录的hash值存到文件p标签的class中,
这样, 点击目录名的时候就可以根据其hash值, 通过getElementsByClass()方法找到所有的下级p标签, 进行显示或隐藏~~

上一步生成嵌套的HTML时
  • 如果是文件就添加一个class="file", id为文件路径的hash值(md5(a/b/c/xxx.md))
  • 如果是中间目录就添加一个class="dir",id为目录路径的hash值(md5(a/b/c))
  • 用file_chain.js 记录下每个文件对应的所有层级的目录的hash值
当用户点击某一个文件后
  • 跳转到此文件的页面
  • 从file_chain.js中找到此文件的所有上层目录
  • 挨个修改其style.display='block'
  • 最后阻止事件冒泡
公用目录
  • 刚开始, 目录是编译后, 每个内容页面中都有, 后来发现增加或删除某个目录时, 没有被修改的页面是不会更新目录的
  • 后来, 将目录HTML代码抽出来放到menu.js中, 每次修改都重洗生成目录, 然后由js动态加载; 这样一来解决了目录公用的问题, 二来减少了内容文件的大小

美化HTML, 支持响应式

首先在css中利用@media属性, 根据屏幕宽度不同使用不同的样式,
其中,
当屏幕宽度大于800px时, 当做PC端, 用css flex将目录和内容同时显示在屏幕中
当屏幕宽度小于800px时, 当做是手机端, 默认将目录隐藏起来, 通过点击右下角的浮动按钮控制目录的显示与隐藏, 显示时铺满屏幕
隐藏目录: 首先将目录div的宽度设为屏幕的宽度(width:100vw), 然后用js将目录的div的左边距设为负值(sidebar.style.margin-left = -window.client.width)达到隐藏目录的效果

手动编译太麻烦

后来发现, 每次用git commit 前要先手动在命令行里编译一下(php compile.php)觉得麻烦,
就给git加了一个hook, 在提交之前自动执行编译命令, 这样就方便多了

最后附上源代码

源代码(码云git)

使用方法(cnblog)

例子

效果图

PC端
手机端1
手机端2


myDCool
48 声望3 粉丝