為部落格園開發了一套腳手架及模板——實時預覽頁面訂製效果
- 2022 年 4 月 6 日
- 筆記
有時大家可能會想為自己的部落格增添一些色彩,但這種熱情卻常常因繁雜的配置步驟飽受消磨。CNBlogX是一套項目模板及腳手架的合集,用於快速搭建部落格園的頁面訂製腳本開發環境。使用方式也非常簡單,專註於自己的程式碼即可。讓我們開始吧!
起步
- 請確保安裝了Node.js,需要14.0或更新的版本。
通過以下命令基於CNBlogX模板創建一個叫做mytheme的項目:
npm init cnblogx mytheme
這樣項目就建立完成了,讓我們看看src/
下的程式碼:
非常簡潔,不必關心CNBlogX在背後做了什麼,我們只要在這三個文件中添加程式碼即可。如果有訂製化的需要,可以查看README.md中的可配置項,接下來讓我們把程式碼部署到部落格園。
首次部署
- 若依賴安裝很慢,可以考慮先配置npm淘寶鏡像源。
首先給我們的項目安裝依賴:
npm install
再編譯我們的項目:
npm run build
然後將dist/
下的生成物複製到部落格園-管理-設置的對應選項中:
- 將
custom.css
的內容複製到頁面訂製CSS程式碼中。 - 將
custom.html
的內容複製到頁腳HTML程式碼中。
最後保存部落格後台設置即可。
首次部署是必要的步驟,CNBlogX在構建時插入了開發者模式相關程式碼,接下來讓我們體驗一下。
開發者模式
- 請確保已經完成首次部署。
首先執行以下命令啟動調試伺服器,它將監視程式碼變化並將其應用到部落格頁面中:
npm run dev
然後瀏覽器中打開自己的部落格,雙擊頁腳的Copyright © 你的名字,進入開發者模式。
此後,若src/
下對應的文件發生了變化,效果將立即應用到部落格頁面中:
main.ejs
:支援HTML/EJS(兼容,後綴不可更改)。main.js
:支援Javascript/Typescript(更改後綴為.ts即可支援Typescript)。main.scss
:支援CSS/SCSS(兼容,後綴不可更改)。
- 再次雙擊頁腳的Copyright © 你的名字,可退出開發者模式。
實踐:編寫常用組件
讓我們寫幾個常用的部落格組件,體驗一下熱模組替換帶來的效率提升吧!後文中出現的組件可以在這個項目中找到。
評論區頭像
第一版:低解析度頭像
部落格園默認不顯示評論區用戶的頭像,但在評論區中提供了每位用戶的頭像鏈接,我們可以通過瀏覽器的開發者工具看到:
所以我們只要通過Javascript新建一個img
標籤,顯示對應鏈接的頭像即可:
嗯… 好像有一點糊,這個頭像解析度太低了。
第二版:回退式高清頭像
經過觀察,我們發現個人主頁的頭像鏈接和評論區的頭像鏈接只存在一個目錄的差異:
那我們可以先顯示這個清晰的頭像,如果獲取失敗了,再回退到低解析度的頭像。效果非常不錯:
第三版:二級回退式頭像
有時候會發現,有的用戶根本沒有上傳頭像,我們可以為他添加一個默認頭像。那麼我們的程式碼至多可能有兩次回退,高清頭像->普通頭像->默認頭像,像這樣:
avatar = document.createElement('img');
avatar.src = get_hi_definition_avatar_src(addr); // 設置為高清頭像。
avatar.addEventListener('error', () => {
if (avatar.src != addr) {
avatar.src = addr; // 回退到低解析度頭像。
} else { // 回退到默認頭像。
avatar.parentNode.replaceChild(new_default_avatar(nick), avatar);
}
});
接下來讓我們給用戶畫一個默認頭像吧!
我們把衣服的位置鏤空,再給頭像元素設置不同的背景色,就可以為不同的用戶顯示不同顏色的頭像了!完整程式碼可以看這裡。
隨筆目錄
雖然Markdown允許通過[toc]
創建一個目錄,但每次都要回到頂部查看目錄並不方便,讓我們也寫一個目錄吧。
棧:將數組轉換為一棵樹
目錄通常是多級的,大標題包含小標題。我們可以用.querySelectorAll()
將文章中所有的標題收集到一個數組中,然後通過一個棧將線性的數組轉化為一棵樹,像這樣:
article.querySelectorAll(SELECTOR_HEADERS).forEach(function (header) {
const node = CreateTocNode(header);
for (; ;) {
if (level(node_stack_top().refel) < level(header)) {
node_stack_top().add_toc_child(node);
node_stack.push(node);
break;
} else {
node_stack.pop();
}
}
});
下一個功能是讓目錄高亮當前小節的標題。
不妨將「當前小節的標題」定義為「離螢幕頂端最近的一個標題」。那麼思路就清晰起來了:註冊一個滾動事件,於事件發生時遍歷所有的標題,找到getBoundingClientRect().top
的絕對值最小的一個,賦予其一個表示高亮的類名即可。
不過,這樸素的思路存在著一定的效率問題,下面我們將對它做出一些優化。
節流:防止滾動事件頻繁觸發
頁面滾動時,滾動事件連續觸發的頻率非常高,可以用一個節流函數降低更新高亮目錄的頻率。同時為了避免節流函數導致丟失滾動快結束時的滾動事件,添加一個會被不斷重置的setTimeout
即可。程式碼是這樣的:
let timeout = null;
regi_scroll(throttle(() => {
update_current_node();
if (!timeout) {
timeout = setTimeout(() => {
update_current_node();
timeout = null;
}, 400);
}
}, 200));
二分搜索:獲取當前小節的標題
標題們的getBoundingClientRect().top
雖然有正有負,但只要是遞增的,就可以應用二分搜索。通過二分搜索找到top
值在零附近的至多兩個標題,再從中取top
的絕對值最小的一個即可。程式碼是這樣的:
let left = 0;
let right = node_list.length - 1;
while (left + 1 < right) {
const mid = Math.floor((left + right) / 2);
if (distance(mid) <= 0) {
left = mid;
} else {
right = mid;
}
}
實現目錄大概用了一百行左右的程式碼,可以在這裡查看。
常見問題
我的項目能夠與其它程式碼共存嗎?
CNBlogX默認會在進入開發者模式時清除用戶的頁面訂製CSS程式碼,以免用戶混淆部署版本與開發版本的樣式,可以通過PRESERVE_CSS
編譯選項阻止這個默認行為。
有離線的文檔嗎?
有的,看項目根目錄下的README.md
。通過腳手架建立的新項目與Github上的模板只有包名不同。
開發者模式會影響他人閱讀嗎?
沒有,開發者模式僅對啟用它的單個瀏覽器有效。
- 要令部落格訂製程式碼對所有讀者生效,需要一次新的部署。
為什麼有時js的更改在刷新後才生效?
因為相關的模組存在未消除的副作用,參考熱模組替換的文檔。
可以單獨生成.js
文件嗎?
可以,通過STANDALONE_JS
編譯選項生成單獨的.js
文件。通過PUBLIC_PATH
編譯選項可令.html
文件從指定的路徑載入.js
文件。
可以自定義埠嗎?
可以,通過PORT
編譯選項配置埠,部落格園中的程式碼與本地測試伺服器的程式碼配置的埠應當相同。
沒有頁腳的部落格如何進入開發者模式?
打開瀏覽器的控制台,執行以下程式碼即可:
cnblogx_development(true);
結語
希望大家喜歡,意見或建議也是很歡迎的,Issue或Pull Request就更歡迎了。