大家好,我是若川。今天分享一篇markdown筆記平臺的項目文章。
點擊下方卡片關注我、加個星標,或者查看源碼等系列文章。學習源碼整體架構系列、年度總結、JS基礎系列

一、前言
作為開發者,我覺的用markdown寫文檔是一件很酷的事情。在之前,想找一款合適自己的markdown平臺做筆記,嘗試用了有道云、印象筆記、作業部落等平臺,挺多功能需要收費或者滿足不了,另外在產品設計上也不是自己想要的style,于是就想著打造一個屬于自己風格的markdown筆記平臺。
二、各平臺markdown筆記差異
1.印象筆記

印象筆記主要專注于word文本編輯,目前web端是不支持markdown語法編寫的。在2018年,印象筆記客戶端開始支持markdown語法。
使用markdown過程中的一些缺陷:
編輯器主題太少
文檔區域代碼不支持主題設置
外鏈訪問有限,僅支持移動端打開,并且下載app才能預覽。
不支持導出md文件、批量導出
2.有道云筆記

有道云也是專注于word文本編輯,支持markdown語法開發。界面相比印象筆記會美觀一點。
使用markdown過程中的一些缺陷:
編輯、預覽區域滾動相對體驗不太友好,有點生硬。
預覽區域代碼不支持主題設置
不支持批量導出
3.其它平臺
比如作業部落,主要專注markdown筆記編寫,由個人開發的平臺,另外一些功能需要收費才能夠使用,功能也比較局限。
總是來說,每個平臺的比較各有各的優勢,同時也存在一些缺陷,由此也萌生了Hbook筆記這個平臺。
三、Hbook筆記
1.介紹
Hbook筆記是一款專注于Markdown筆記的平臺。

特性:
支持編輯器、文檔區域主題任意切換
支持編輯、文檔區域調整窗口大小
支持單個、批量導出md文件
支持文檔截圖
文檔目錄
文章支持分類
支持控制外鏈訪問
擁有自己的個人主頁
2.如何實現?
這是整個項目的一個架構圖:

完成這么個項目,你需要具備的一些基本能力和條件:
[x] 一個域名
[x] 一臺服務器(阿里云、騰訊云)
[x] web開發
[x] nodejs開發
[x] 安裝node
[x] 安裝pm2
[x] 安裝nginx
[x] 安裝mysql
[x] 安裝redis
看著好像有點多?我已經為你準備好了教程,一步步教你如何安裝部署。
安裝部署教程[1]
前臺實現
前臺頁面的核心實現其實就是編輯器,這里選用的是第三方 brace[2] 插件 ,brace支持各種語言的編輯器,這里選用 markdown
語法。
核心基礎配置:
import?ace?from?'brace'
import?'brace/mode/markdown'
editor?=?ace.edit('editor');
editor.focus();//?設置字體?請勿用亂用字體,否則會影響光標位置問題,
editor.setOption('fontFamily',?'Menlo,?'Ubuntu?Mono',?Consolas,?'Courier?New',?'Microsoft?Yahei',?'Hiragino?Sans?GB',?'WenQuanYi?Micro?Hei',?'sans-serif');
//?設置字體大小
editor.setOption('fontSize',?'18px');
//?設置內容
editor.setValue(editContent);
//?清除選中
editor.clearSelection();
//?設置編輯器語言模式
editor.getSession().setMode('ace/mode/markdown');
//?設置皮膚
vm.changeEditorSkin(vm.themeData.editor)
//自動換行,設置為off關閉
editor.setOption('wrap',?'free')
//?設置是否只讀
editor.setReadOnly(true?||?false);?
//?是否展示行號
editor.setOption('showGutter',?false);
editor.setOption('autoScrollEditorIntoView',?true);
//?使用軟標簽
editor.getSession().setUseSoftTabs(false);
//?線條
editor.renderer.setShowPrintMargin(false);
//?設置編輯器左右邊距
editor.renderer.setPadding(35);
在用的過程中值得注意的事:
請勿用亂用字體,建議用默認就行,否則會影響光標位置問題。

編輯器內容保存后出現xss問題,需要對文章內容相應的標簽進行處理。
另外拿到文本之后,你需要把markdown語法轉化成html展示,這里選用第三方 showdown[3] ?插件,詳情文檔可點擊查看。
使用示例:
import?showdown?from?'showdown'
const?converter?=?new?showdown.Converter({tables:true,tasklists:true,ghCodeBlocks:true,simpleLineBreaks:true,openLinksInNewWindow:true,backslashEscapesHTMLTags:true
});
const?content?=?converter.makeHtml(val);
預覽展示已經實現了,自然目錄也少不了,目錄只要把相應的標題標簽全部找出來就行了,然后給每個不同的標題做一些不同層級的樣式間距即可,大概實現方式:
const?vm?=?this;
vm.anchorDom?=?[];const?anchorList??=?rc.querySelectorAll('h1,h2,h3,h4,h5,h6');anchorList.forEach(function(elem,index){const?tag?=?elem.localName;vm.anchorDom.push({index:index,tag:tag,text:elem.innerText})elem.setAttribute('id','anchor-'+index);
})
另外編輯器滾動的時候預覽區域也要相應的滾動到相應到位置,這邊采用比較簡單的方式,算出2個區域的高度比。
//?計算2邊高度的占比
getScale()?{const?rightDiff?=?rc.offsetHeight?-?right.offsetHeight?+?50;?//預覽內容高度減去盒子固定的高度const?leftDiff?=?editor.renderer.layerConfig.maxHeight?-?left.offsetHeight;?//編輯內容高度減去該盒子固定的高度return?rightDiff?/?leftDiff;
}
然后監聽2邊的滾動事件做相應的處理:
//?編輯區滾動
editScroll()?{const?scale?=?this.getScale();right.scrollTop?=?left.scrollTop?*?scale
}
//?展示區滾動
showScroll()?{const?scale?=?this.getScale();editor.getSession().setScrollTop(right.scrollTop?/?scale);
}
另外考慮到編輯器、預覽區域大小靈活問題,在中間滾動條也實現了可縮小或者擴大區域,根據自己喜好來調整,具體實現方式就是監聽 mousemove
事件然后改變左右2邊的寬度即可。
左邊菜單獲取到文章列表時需要生成樹結構,實現方式:
/***?無限分類格式化成樹*/
function?toTree(data){//?刪除?所有?children,以防止多次調用data.forEach(function(item)?{delete?item.children;});//?將數據存儲為?以?id?為?KEY?的?map?索引數據列var?map?=?{};data.forEach(function(item,?index)?{map[item.id]?=?item;});var?val?=?[];data.forEach(function(item)?{//?以當前遍歷項,的pid,去map對象中找到索引的idvar?parent?=?map[item.parent_id];//?如果找到索引,那么說明此項不在頂級當中,那么需要把此項添加到,他對應的父級中if?(parent)?{(parent.children?||?(parent.children?=?[])).push(item);}?else?{//如果沒有在map中找到對應的索引ID,那么直接把?當前的item添加到?val結果集中,作為頂級val.push(item);}});return?val;
}
后臺實現
后臺技術這里主要采用nodejs,核心主要在表結構設計上,其它的相對還好。
這個項目的一個表結構設計,僅夠大家參考了解:
用戶表
字段 | 類型 | 是否必填 | 備注 |
---|---|---|---|
id | Number | 是 | id |
username | String | 是 | 用戶名 |
password | String | 是 | 密碼 |
String | 否 | 郵件 | |
nickname | String | 是 | 昵稱 |
mobile | String | 否 | 手機 |
desc | String | 否 | 描述 |
avatar | String | 否 | 頭像 |
province | String | 否 | 省份 |
city | String | 否 | 城市 |
source | String | 是 | 來源 |
status | Number | 是 | 狀態 |
文章分類表
字段 | 類型 | 是否必填 | 備注 |
---|---|---|---|
id | Number | 是 | id |
user_id | Number | 是 | 用戶ID |
parent_id | Number | 是 | 父級分類ID,0為第一級 |
category_name | String | 是 | 分類名稱 |
文章表
字段 | 類型 | 是否必填 | 備注 |
---|---|---|---|
id | Number | 是 | id |
title | String | 是 | 標題 |
content | TEXT | 否 | 文章內容 |
state | Number | 是 | 文章狀態 0 未對外開放 1 對外開放 2 禁止文章 |
password | String | 否 | 文章訪問密碼 |
browser_num | INTEGER | 是 | 閱讀數 |
另外可對文章內容設置的標簽進行更細一步進行分類,通過標簽篩選出相對應的文章,這個實現邏輯比較復雜就不講了,有興趣的可以交流下。
基本上滿足以上3個表就可以搭建自己的一個文章庫了。
3.后續優化
實現文章密碼訪問權限
新增導出pdf文件
編輯器文本過濾非法標簽
兩邊滾動區域更加精準
4.愿景
愿景:讓筆記成為一種習慣,讓分享成為一種快樂。
5.最后
原本的初心弄個筆記出來玩玩,但沒想到自己做出來后卻養成了一個寫筆記的習慣,記錄了工作上的點點滴滴,讓自己也收獲匪淺。
最后歡迎體驗該產品,提出您寶貴的建議。Hbook[4]

四、總結
通過上面的講解,相信你對整個流程也基本熟悉,自己也可以嘗試動起來,有啥問題歡迎一起交流。
參考資料
[1]
安裝部署教程: http://bookcss.com/note/12/14
[2]brace: https://github.com/thlorenz/brace
[3]showdown: https://github.com/showdownjs/showdown
[4]Hbook: http://bookcss.com
最近組建了一個江西人的前端交流群,如果你也是江西人可以加我微信 ruochuan12 拉你進群。
·················?若川出品?·················
今日話題
大家都知道項目經驗很重要,如果有空不妨也試著做一個筆記平臺,或者簡歷平臺,相信能學到很多。歡迎在下方留言~? 歡迎分享、收藏、點贊、在看我的公眾號文章~
一個愿景是幫助5年內前端人走向前列的公眾號
可加我個人微信?ruochuan12,長期交流學習
推薦閱讀
我在阿里招前端,我該怎么幫你?(現在還能加我進模擬面試群)
若川知乎問答:2年前端經驗,做的項目沒什么技術含量,怎么辦?
點擊上方卡片關注我、加個星標,或者查看源碼等系列文章。
學習源碼整體架構系列、年度總結、JS基礎系列