航頁(yè):onenav 4.0510 主題定制完全指南)
簡(jiǎn)介瀏覽器收藏夾一多就亂傳統(tǒng)書簽工具又受限于同步和隱私。自托管導(dǎo)航頁(yè)成為個(gè)人與團(tuán)隊(duì)整理高頻入口的輕量方案?;?onenav 這類 PHPSQLite 程序無(wú)需復(fù)雜環(huán)境即可快速部署數(shù)據(jù)文件備份即遷移。主題系統(tǒng)支持模板與樣式分離借助 CSS Grid 卡片布局、CSS 變量和暗色模式能輕松改出符合日常操作習(xí)慣的視覺(jué)風(fēng)格。同時(shí)可整合搜索框、圖標(biāo)回退、鏈接失效監(jiān)控等工程化細(xì)節(jié)讓導(dǎo)航頁(yè)真正替代瀏覽器首頁(yè)成為統(tǒng)一入口。本文從部署環(huán)境、主題文件結(jié)構(gòu)到性能優(yōu)化梳理了定制一套專屬導(dǎo)航主題的完整路徑。 有導(dǎo)航需求的人大多經(jīng)歷過(guò)同一個(gè)階段瀏覽器收藏夾里堆了幾百條鏈接想著“等有空整理一下”結(jié)果越攢越亂最后干脆靠搜索硬找。我折騰 onenav 導(dǎo)航主題就是從這種狀態(tài)開始的。這套基于 onenav 4.0510 版本定制出來(lái)的導(dǎo)航主題不只是把鏈接換了個(gè)地方放而是直接替代了瀏覽器首頁(yè)把常用工具、資料、內(nèi)部系統(tǒng)入口全部統(tǒng)一到一個(gè)頁(yè)面里。今天這篇就聊聊我為什么選 onenav、怎么部署、怎么從默認(rèn)主題改出自己的一套導(dǎo)航主題以及上線之后踩過(guò)的那些坑。如果你正準(zhǔn)備搭個(gè)人導(dǎo)航站、團(tuán)隊(duì)內(nèi)部導(dǎo)航頁(yè)或者只是想給瀏覽器換個(gè)更順手的起始頁(yè)這篇文章應(yīng)該能幫你少走不少?gòu)澛贰N也粚懩欠N浮在表面的大道理全部是實(shí)際操作過(guò)的步驟、代碼和排查思路。1. 為什么我把收藏夾扔了改用 onenav 自己搭導(dǎo)航頁(yè)1.1 瀏覽器收藏夾的“失控曲線”先坦白我之前的狀況書簽欄放了十幾個(gè)文件夾每個(gè)文件夾里又套子文件夾最深的層級(jí)能點(diǎn)四五層才能到目標(biāo)網(wǎng)站。這還不算最麻煩的——真正的問(wèn)題是收藏夾的搜索能力極弱分類只能靠手工拖拽而且換一臺(tái)電腦、換一個(gè)瀏覽器書簽同步還得看賬號(hào)和網(wǎng)絡(luò)狀態(tài)。后來(lái)也試過(guò)在線書簽工具但要么是功能太重要么是把數(shù)據(jù)存在別人的服務(wù)器上隱私和訪問(wèn)速度總有一個(gè)讓我不舒服。再加上我自己的使用場(chǎng)景里有大量“只對(duì)內(nèi)部開放”的系統(tǒng)地址這些東西放在第三方平臺(tái)上本身就是隱患。于是我把目光轉(zhuǎn)向了自托管導(dǎo)航頁(yè)自己買一個(gè)小服務(wù)器或者直接部署在已有的 VPS、NAS 上通過(guò)網(wǎng)頁(yè)的方式把所有鏈接統(tǒng)一管理。好處是數(shù)據(jù)完全自主可控?fù)Q設(shè)備只需要開個(gè)網(wǎng)頁(yè)登錄分類、排序、圖標(biāo)全都可以自定義。1.2 為什么是 onenav 而不是其他導(dǎo)航程序市面上類似的工具我至少試過(guò)五六個(gè)包括純靜態(tài)的 HTML 導(dǎo)航頁(yè)、Flarum 之類的論壇式書簽、還有一些用 TypeScript 寫的新項(xiàng)目。對(duì)比下來(lái)onenav 有幾個(gè)優(yōu)勢(shì)非常突出部署簡(jiǎn)單它是個(gè) PHP 程序環(huán)境要求不高一臺(tái)內(nèi)存 512MB 的小機(jī)器就能跑得動(dòng)。數(shù)據(jù)存儲(chǔ)輕量默認(rèn)用 SQLite不需要單獨(dú)裝 MySQL備份就是一個(gè)文件。自帶后臺(tái)管理分類、鏈接、主題、站點(diǎn)設(shè)置都能在網(wǎng)頁(yè)后臺(tái)完成不需要改代碼。主題系統(tǒng)清晰模板、樣式、腳本分離改起來(lái)比那些“一鍵生成導(dǎo)航頁(yè)”的工具靈活得多。中文生態(tài)友好文檔和社區(qū)討論大多是中文遇到問(wèn)題搜一下就能解決。至于這套導(dǎo)航主題為什么叫 4.0510其實(shí)就是我這邊的內(nèi)部版本號(hào)。我一開始用的是 onenav 官方默認(rèn)主題但用了一周就發(fā)現(xiàn)默認(rèn)主題的布局太“工具化”首頁(yè)直接平鋪一堆鏈接視覺(jué)上沒(méi)什么層次。4.0510 是我從默認(rèn)主題的模板結(jié)構(gòu)出發(fā)重做卡片樣式、間距、圖標(biāo)體系和響應(yīng)式布局之后定下來(lái)的版本號(hào)后面所有的改動(dòng)都以這套主題為基礎(chǔ)。1.3 這套主題適合誰(shuí)個(gè)人用戶想給瀏覽器一個(gè)清爽的起始頁(yè)把高頻站點(diǎn)、常用工具、待辦入口集中起來(lái)。小團(tuán)隊(duì)/小組把項(xiàng)目文檔、代碼倉(cāng)庫(kù)、監(jiān)控面板、會(huì)議鏈接統(tǒng)一放一個(gè)導(dǎo)航頁(yè)省得每天口頭傳遞網(wǎng)址。服務(wù)器愛(ài)好者有一臺(tái)閑置 VPS/NAS想讓它發(fā)揮一點(diǎn)實(shí)際作用。如果你只想“放幾個(gè)鏈接完事”那也確實(shí)沒(méi)必要上這套東西但如果你像我一樣有幾十上百個(gè)入口需要組織并且希望頁(yè)面既好看又能快速到達(dá)那這套方案是劃算的。2. 部署 onenav 4.x環(huán)境選擇、安裝步驟與首登配置2.1 環(huán)境需求別再犯裝不上程序的低級(jí)錯(cuò)誤onenav 對(duì)運(yùn)行環(huán)境的要求其實(shí)很低但恰恰因?yàn)椤暗汀焙芏嗳朔炊豢次臋n直接裝最后因?yàn)槿睌U(kuò)展卡在半路。我這邊梳理一份可以照抄的清單項(xiàng)目建議配置備注PHP 版本PHP 7.4 及以上建議 PHP 8.0/8.1PHP 8.2 也可能沒(méi)問(wèn)題但有些第三方擴(kuò)展會(huì)兼容性翻車必裝擴(kuò)展PDO、SQLite3、curl、mbstring、openssl沒(méi)有 SQLite3 的話安裝階段就會(huì)直接報(bào)錯(cuò)Web 服務(wù)器Nginx 或 Apache 均可個(gè)人更推薦 Nginx偽靜態(tài)配置更順手系統(tǒng)Linux 優(yōu)先Windows/macOS 也能跑生產(chǎn)環(huán)境建議 Linux最低內(nèi)存512MB 以上1GB 會(huì)更寬裕我在部署時(shí)用的是寶塔面板加 Nginx 的組合PHP 版本選的 8.0。安裝過(guò)程中遇到過(guò)最典型的兩個(gè)問(wèn)題一是 PHP 沒(méi)裝 SQLite 擴(kuò)展安裝界面直接白屏二是打開安裝向?qū)r(shí)目錄權(quán)限不對(duì)導(dǎo)致無(wú)法寫入配置文件。這兩個(gè)問(wèn)題在下面的安裝步驟里我會(huì)特別標(biāo)注。2.2 從下載到跑起來(lái)三種安裝方式方式一直接下載源碼部署到 onenav 的發(fā)布頁(yè)面下載最新版本的壓縮包解壓到站點(diǎn)根目錄比如/www/wwwroot/nav.example.com。然后設(shè)置運(yùn)行目錄把站點(diǎn)運(yùn)行目錄指向public這一步很關(guān)鍵不然訪問(wèn)首頁(yè)會(huì)直接暴露目錄結(jié)構(gòu)。接著在站點(diǎn)配置里加一條偽靜態(tài)規(guī)則。我的 Nginx 配置如下Apache 用戶可以直接用程序自帶的.htaccesslocation / { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s$1 last; } }配置好之后在瀏覽器訪問(wèn)你的域名會(huì)進(jìn)入安裝向?qū)?。填入站點(diǎn)名稱、管理員賬號(hào)密碼、數(shù)據(jù)庫(kù)類型保持 SQLite 即可下一步就會(huì)生成配置文件。如果安裝頁(yè)面提示權(quán)限問(wèn)題記得給data目錄和根目錄寫入權(quán)限chmod -R 755 /www/wwwroot/nav.example.com chmod -R 777 /www/wwwroot/nav.example.com/data方式二Docker 部署如果你不想在宿主機(jī)上折騰 PHP 環(huán)境Docker 是最省事的方式。我測(cè)試過(guò)用下面這個(gè)組合跑 onenav 4.x穩(wěn)定運(yùn)行了大半年version: 3 services: onenav: image: helloz/onenav:latest container_name: onenav ports: - 8080:80 volumes: - ./data:/data/wwwroot/default/data restart: unless-stopped啟動(dòng)之后瀏覽器訪問(wèn)http://服務(wù)器IP:8080同樣會(huì)進(jìn)入安裝向?qū)АP枰⒁?Docker 版本的數(shù)據(jù)目錄必須掛載出來(lái)否則容器刪掉后數(shù)據(jù)就全沒(méi)了。方式三內(nèi)網(wǎng) NAS 部署如果你的 NAS 支持 Docker也可以直接跑。我的實(shí)際經(jīng)驗(yàn)是內(nèi)網(wǎng)部署時(shí)不需要做端口映射只需要在路由器上保留內(nèi)網(wǎng)訪問(wèn)即可。當(dāng)然如果想在外網(wǎng)訪問(wèn)那就需要用到反向代理不建議直接把端口裸奔到公網(wǎng)。2.3 登錄后臺(tái)后第一件事改什么onenav 裝好后默認(rèn)的頁(yè)面和功能都比較“原始”你需要花幾分鐘把下面幾項(xiàng)設(shè)置改好后面再折騰主題時(shí)才能順心設(shè)置項(xiàng)我的建議說(shuō)明基礎(chǔ)設(shè)置里的站點(diǎn)名稱改成你的實(shí)際名稱會(huì)顯示在瀏覽器標(biāo)題和首頁(yè)頭部別留默認(rèn)的鏈接打開方式新窗口打開導(dǎo)航頁(yè)的跳出率很低保持新窗口打開才不會(huì)讓用戶迷路登錄密碼和 Token一定要改默認(rèn)值后臺(tái)默認(rèn)賬號(hào)密碼登錄后立即更新是否開啟注冊(cè)單人或團(tuán)隊(duì)內(nèi)部用就徹底關(guān)掉避免陌生人進(jìn)來(lái)亂改分類站點(diǎn)統(tǒng)計(jì)按需接入不接也沒(méi)關(guān)系但接了能看到哪些鏈接被點(diǎn)得最多還有一點(diǎn)容易被忽略如果是在 HTTP 環(huán)境里跑建議盡早給站點(diǎn)加上 SSL 證書不然瀏覽器會(huì)一直提示“不安全”不僅難看還會(huì)影響搜索框的自動(dòng)填充等功能。用 Let‘s Encrypt 或?qū)毸姘宓囊绘I SSL 都行。3. 主題文件結(jié)構(gòu)解析改主題前必須知道的三件事3.1 主題目錄里到底哪些文件說(shuō)了算onenav 的主題文件都在app/view/目錄下默認(rèn)主題是default。我自己做的 4.0510 主題實(shí)際上是在這個(gè)目錄下新建了一個(gè)mytheme文件夾再?gòu)哪J(rèn)主題拷貝出核心模板文件來(lái)改。這樣做的最大好處是程序升級(jí)時(shí)不會(huì)覆蓋你的自定義文件即使覆蓋了也只是覆蓋了default你的mytheme依然保持完整。主題文件結(jié)構(gòu)大致如下app/view/mytheme/ ├── admin.php # 后臺(tái)管理模板一般不用動(dòng) ├── footer.php # 頁(yè)腳模板 ├── header.php # 頁(yè)頭模板包含 HTML head、CSS、JS 引入 ├── index.php # 首頁(yè)主模板導(dǎo)航分類和鏈接的核心渲染邏輯 ├── login.php # 登錄頁(yè)模板 ├── assets/ │ ├── css/ # 樣式文件 │ └── js/ # 交互腳本如果你只想做局部美化核心看兩個(gè)文件header.php和index.php。前者控制整個(gè)頁(yè)面的頭部和公共樣式引入后者決定導(dǎo)航內(nèi)容的排列方式。3.2 通過(guò)模板變量理解數(shù)據(jù)渲染邏輯第一次打開index.php的時(shí)候你會(huì)發(fā)現(xiàn)里面夾雜著很多?php echo $xxx; ?這種寫法。這是 onenav 自研模板引擎的輸出方式不是亂碼。你只需要掌握最常用的幾個(gè)變量$webconf[site_name] // 站點(diǎn)名稱 $webconf[site_desc] // 站點(diǎn)描述 $categorys // 全部分類數(shù)據(jù)循環(huán)輸出 $links // 當(dāng)前分類下的鏈接集合 $current_cate // 當(dāng)前選中的分類最簡(jiǎn)單的理解方式是$categorys是一個(gè)二層結(jié)構(gòu)外層是分類內(nèi)層是該分類下的鏈接數(shù)組。首頁(yè)模板的循環(huán)邏輯大概長(zhǎng)這樣?php foreach ($categorys as $cate) : ? div classnav-category h2 classcategory-title?php echo $cate[name]; ?/h2 div classcategory-links ?php foreach ($cate[links] as $link) : ? a classnav-item href?php echo $link[url]; ? target_blank img src?php echo $link[icon]; ? alt span classlink-title?php echo $link[title]; ?/span /a ?php endforeach; ? /div /div ?php endforeach; ?把這個(gè)結(jié)構(gòu)看懂之后主題改造就變成了一件事——修改這些 HTML 標(biāo)簽和 CSS 類名把它從“平鋪列表”變成你想要的“卡片網(wǎng)格”。3.3 我為什么把導(dǎo)航鏈接設(shè)計(jì)成“卡片圖標(biāo)優(yōu)先”默認(rèn)主題里每個(gè)鏈接都是一個(gè)純文字列表一眼掃過(guò)去分不清主次。4.0510 主題里我把每個(gè)鏈接改成了卡片式按鈕左側(cè)或上方是網(wǎng)站圖標(biāo)下面跟著標(biāo)題。這樣做的原因有兩個(gè)一是視覺(jué)上有“按鈕感”鼠標(biāo)點(diǎn)起來(lái)更自然二是圖標(biāo)能幫助眼睛快速定位目標(biāo)特別是當(dāng)你的導(dǎo)航頁(yè)里有十幾個(gè)同類站點(diǎn)時(shí)一張臉比一段文字更容易認(rèn)。實(shí)現(xiàn)方式不復(fù)雜核心就是 CSS Grid 布局加上圖標(biāo)處理。后面我會(huì)詳細(xì)展開。4. 視覺(jué)重構(gòu)實(shí)操?gòu)牟季?、配色到字體的一步步改造4.1 用 CSS 變量統(tǒng)一主題色調(diào)改配色不再全站亂找很多人在改導(dǎo)航主題時(shí)容易掉進(jìn)“這里改一下、那里改一下”的坑最后頁(yè)面紅不紅藍(lán)不藍(lán)看起來(lái)像拼貼畫。我的做法是先定義一組 CSS 變量把顏色、圓角、間距全部抽象出來(lái)后續(xù)只需要改變量全站風(fēng)格就統(tǒng)一了。在assets/css/main.css頂部加這么一段:root { --bg-primary: #f5f7fb; /* 頁(yè)面背景 */ --bg-card: #ffffff; /* 卡片背景 */ --text-primary: #1f2937; /* 主文字 */ --text-secondary: #6b7280; /* 次級(jí)文字 */ --accent: #4f6ef7; /* 強(qiáng)調(diào)色 */ --radius: 12px; /* 卡片圓角 */ --shadow: 0 2px 8px rgba(0, 0, 0, 0.06); --max-width: 1200px; /* 內(nèi)容最大寬度 */ }之后在.nav-item、.category-title等樣式中直接用這些變量。如果你想做暗色模式只需要在后半夜時(shí)間段切換body上的一個(gè)類名然后把變量重新賦值即可。4.2 卡片網(wǎng)格的寫法和斷點(diǎn)設(shè)計(jì)4.0510 主題的布局核心是網(wǎng)格而不是傳統(tǒng)的浮動(dòng)或 Flex 換行。用 Grid 的好處是卡片寬度自動(dòng)適配而且不用寫一堆 margin hack。.nav-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 16px; } .nav-item { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 20px 12px; background: var(--bg-card); border-radius: var(--radius); box-shadow: var(--shadow); transition: transform 0.2s ease, box-shadow 0.2s ease; text-decoration: none; } .nav-item:hover { transform: translateY(-4px); box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12); } .nav-item img { width: 40px; height: 40px; border-radius: 10px; margin-bottom: 10px; object-fit: contain; } .link-title { font-size: 14px; color: var(--text-primary); text-align: center; line-height: 1.4; }這個(gè)布局有一個(gè)很實(shí)用的特性minmax(160px, 1fr)表示每個(gè)卡片最小 160px 寬如果屏幕夠?qū)捑W(wǎng)格會(huì)自動(dòng)把額外的空間分給每一列。手機(jī)上訪問(wèn)時(shí)卡片自動(dòng)從一行五六個(gè)變成一行兩三個(gè)不需要額外寫媒體查詢。不過(guò)也要提一個(gè)容易踩的小坑如果你在卡片里使用了box-shadow在低性能手機(jī)上列表很長(zhǎng)時(shí)可能會(huì)有輕微掉幀。解決辦法是把 hover 的陰影過(guò)渡改成opacity過(guò)渡或者干脆不要 transform 位移我實(shí)測(cè)去掉 transform 后滾動(dòng)流暢度明顯提升。4.3 首頁(yè)首屏LOGO、搜索框和快捷入口導(dǎo)航頁(yè)的“首屏”很重要因?yàn)橛脩舻淖⒁饬κ紫嚷湓谀抢?。我?4.0510 主題首頁(yè)首屏從上到下依次是頂部站點(diǎn) LOGO 和名稱做成居中的低調(diào)樣式一個(gè)巨大的搜索框支持直接跳轉(zhuǎn)百度、必應(yīng)、GitHub 等搜索源下面緊接著就是導(dǎo)航分類和鏈接卡片區(qū)。搜索框的實(shí)現(xiàn)其實(shí)不復(fù)雜我用了 onenav 自帶的搜索功能只需要在header.php里加入一個(gè)簡(jiǎn)單的表單即可。如果你想讓搜索框支持多引擎切換可以做成一個(gè)下拉選擇框把a(bǔ)ction指向不同搜索引擎的請(qǐng)求地址。form classsearch-box actionhttps://www.bing.com/search methodget target_blank select nameengine option valuebing必應(yīng)/option option valuebaidu百度/option option valuegithubGitHub/option /select input typetext nameq placeholder搜索一下... autocompleteoff button typesubmit搜索/button /form如果你用的是其他搜索引擎形式也差不多反正都是 GET 請(qǐng)求把q參數(shù)帶過(guò)去就行。這一步做完導(dǎo)航頁(yè)的“工具屬性”就立起來(lái)了不再是單純的一堆鏈接。4.4 暗色模式的實(shí)現(xiàn)思路暗色模式是很多人一上來(lái)就想要的功能但實(shí)現(xiàn)得不好會(huì)適得其反。我用的方案是給body加一個(gè).dark類然后重新定義 CSS 變量body.dark { --bg-primary: #111827; --bg-card: #1f2937; --text-primary: #f9fafb; --text-secondary: #9ca3af; --accent: #8196ff; --shadow: 0 2px 8px rgba(0, 0, 0, 0.4); }切換邏輯放在assets/js/darkmode.js里根據(jù)本地存儲(chǔ)記錄用戶偏好const toggleDark () { document.body.classList.toggle(dark); localStorage.setItem(theme, document.body.classList.contains(dark) ? dark : light); }; if (localStorage.getItem(theme) dark) { document.body.classList.add(dark); }暗色模式不只影響背景色卡片里的圖標(biāo)、文字、搜索框邊框都要跟著變。所以一定要用 CSS 變量而不是寫死顏色。5. 分類、圖標(biāo)與排序把導(dǎo)航頁(yè)做成本地“總?cè)肟凇?.1 分類邏輯別按“網(wǎng)站類型”分要按“使用場(chǎng)景”分很多人給導(dǎo)航分類時(shí)下意識(shí)按“技術(shù)”“生活”“娛樂(lè)”這種方式分組但實(shí)際使用中你會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題一個(gè)網(wǎng)站可能同時(shí)屬于多個(gè)場(chǎng)景。比如“GitHub”既是開發(fā)工具又是學(xué)習(xí)資料還是日常逛的社區(qū)。硬分類就會(huì)糾結(jié)。我的做法是按“使用場(chǎng)景”分組而不是“網(wǎng)站類型”場(chǎng)景分組包含示例為什么這樣分每日必開郵箱、日歷、待辦、新標(biāo)簽頁(yè)上班第一件事就點(diǎn)它開發(fā)工具箱GitHub、代碼片段、JSON 格式化、API 文檔寫代碼過(guò)程中頻繁切換內(nèi)網(wǎng)系統(tǒng)路由后臺(tái)、NAS、監(jiān)控面板不需要記 IP入口統(tǒng)一資訊與社區(qū)技術(shù)論壇、新聞、博客閱讀場(chǎng)景集中分類名稱可以短一點(diǎn)一兩個(gè)字最好導(dǎo)航頁(yè)不是文章目錄不需要解釋得很清楚。后臺(tái)“分類管理”里可以直接拖動(dòng)排序把最常用的放在前面。5.2 圖標(biāo)方案從 favicon 到自定義圖標(biāo)的完整鏈路導(dǎo)航鏈接的圖標(biāo)是決定頁(yè)面美觀度的關(guān)鍵之一。onenav 本身有“自動(dòng)拉取網(wǎng)站 favicon”的功能但實(shí)際體驗(yàn)并不理想有些網(wǎng)站的 favicon 加載慢有些干脆沒(méi)有還有的低分辨率圖標(biāo)放大后糊成一片。我在 4.0510 主題里采用的圖標(biāo)策略是三級(jí)回退優(yōu)先使用后臺(tái)手動(dòng)上傳的自定義圖標(biāo)。沒(méi)有自定義圖標(biāo)時(shí)使用https://favicon.im/{域名}這類公開 favicon 服務(wù)。如果 favicon 獲取失敗顯示一個(gè)首字母占位圖標(biāo)。后臺(tái)添加鏈接時(shí)圖標(biāo)地址可以填本地路徑或遠(yuǎn)程 URL。如果你有一堆站點(diǎn)要批量加可以寫個(gè)簡(jiǎn)單的 Python 腳本把站點(diǎn)域名批量替換成圖標(biāo)地址https://favicon.im/example.com另外圖標(biāo)是有緩存的。如果你改了某個(gè)鏈接的圖標(biāo)但首頁(yè)還是舊圖多半是瀏覽器緩存或 onenav 的圖標(biāo)緩存目錄里存了舊文件。清理一下data/下的緩存目錄再?gòu)?qiáng)制刷新瀏覽器一般就能解決。5.3 鏈接排序的隱藏規(guī)則前臺(tái)導(dǎo)航分類里的鏈接排序后臺(tái)有個(gè)“排序”數(shù)值字段數(shù)字越小越靠前。但這里有個(gè)容易誤解的點(diǎn)不是所有鏈接都按全局排序同一個(gè)分類下的鏈接之間才是按這個(gè)值排序。所以如果你想微調(diào)某個(gè)分類內(nèi)部順序直接在后臺(tái)改對(duì)應(yīng)鏈接的排序值即可。我也見過(guò)有人在鏈接標(biāo)題里加數(shù)字前綴來(lái)手動(dòng)排序比如“01-郵箱”“02-日歷”這種做法的缺點(diǎn)是一旦要插入新鏈接后面所有前綴都要改。后來(lái)我寫了一個(gè)小 SQL 腳本批量調(diào)整排序省了不少事建議你直接在后臺(tái)拖動(dòng)排序就好不用搞花活。6. 主題上線后的性能優(yōu)化與常見坑排查6.1 慢頁(yè)面排查PHP-FPM、SQLite 與緩存onenav 本身很輕量但如果你在一個(gè)性能很差的虛擬主機(jī)上跑還是可能出現(xiàn)打開首頁(yè)要兩三秒的情況。第一步先確認(rèn)瓶頸出在哪。我一般是這樣排查的看 Nginx 訪問(wèn)日志確認(rèn)是動(dòng)態(tài)請(qǐng)求慢還是靜態(tài)資源慢。靜態(tài)資源慢就開 CDN 或優(yōu)化圖片動(dòng)態(tài)慢就往下查。打開 PHP-FPM 的慢日志例如寶塔面板里設(shè)置request_slowlog_timeout 5s然后看踩點(diǎn)日志。如果慢日志里定位到index.php和 SQLite 查詢大概率是數(shù)據(jù)量太大導(dǎo)致全表掃描。鏈接數(shù)量達(dá)到幾千條時(shí)SQLite 的查詢性能會(huì)明顯下降。對(duì)于絕大多數(shù)個(gè)人導(dǎo)航站鏈接數(shù)量不會(huì)超過(guò)幾百條這種規(guī)模下 SQLite 完全夠用。真到了幾千條的規(guī)模建議考慮往 MySQL 遷移onenav 后臺(tái)可以直接切換數(shù)據(jù)庫(kù)類型數(shù)據(jù)導(dǎo)入導(dǎo)出也比較成熟。另外onenav 自帶頁(yè)面緩存功能在“設(shè)置”里開啟后頁(yè)面會(huì)生成靜態(tài) HTML 文件后續(xù)請(qǐng)求直接命中緩存速度和純靜態(tài)頁(yè)差不多。代價(jià)是修改鏈接、分類后需要手動(dòng)更新緩存否則前臺(tái)看不到變化。我平時(shí)是“開發(fā)時(shí)關(guān)緩存上線后開緩存”這個(gè)節(jié)奏比較舒服。6.2 升級(jí)程序時(shí)我的主題會(huì)不會(huì)被覆蓋這是我最擔(dān)心也最常被問(wèn)到的問(wèn)題。onenav 升級(jí)時(shí)官方包里的app/view/default會(huì)被覆蓋但只要你按照前面提到的做法把主題放在一個(gè)新的文件夾里比如mytheme然后到后臺(tái)主題設(shè)置里選擇這個(gè)主題理論上就不會(huì)被升級(jí)流程動(dòng)到。但也有兩個(gè)意外情況值得提醒后臺(tái)的“主題設(shè)置”里如果勾選了自動(dòng)更新相關(guān)選項(xiàng)可能會(huì)自動(dòng)去下載主題更新覆蓋你的自定義文件。我建議關(guān)掉自動(dòng)更新手動(dòng)做備份。升級(jí)前先備份data目錄和app/view/mytheme目錄。備份方式很簡(jiǎn)單直接打包整個(gè)站點(diǎn)目錄或使用后臺(tái)的備份功能。我升級(jí) onenav 4.x 到新版本的常規(guī)流程是先打包舊站點(diǎn)目錄再上傳新版本源碼保留data目錄和自定義主題目錄然后執(zhí)行升級(jí)腳本。目前跑了幾次都沒(méi)出問(wèn)題。6.3 鏈接失效與站點(diǎn)可用性監(jiān)控導(dǎo)航頁(yè)的最大痛苦是“死鏈”別人點(diǎn)了一個(gè)鏈接半天打不開體驗(yàn)很糟。onenav 本身沒(méi)有內(nèi)置鏈接監(jiān)控功能我的做法是寫了一個(gè)簡(jiǎn)單的爬蟲腳本每個(gè)月跑一次把所有鏈接抓一遍返回非 200 狀態(tài)碼的標(biāo)記出來(lái)。腳本邏輯不復(fù)雜import sqlite3 import requests conn sqlite3.connect(data/onenav.db) cursor conn.cursor() cursor.execute(SELECT id, url FROM links) rows cursor.fetchall() for link_id, url in rows: try: resp requests.head(url, timeout5, allow_redirectsTrue) if resp.status_code ! 200: print(f鏈接失效: {url} - {resp.status_code}) except Exception as e: print(f請(qǐng)求異常: {url} - {e})這個(gè)腳本可以放到服務(wù)器的 crontab 里定時(shí)執(zhí)行結(jié)果輸出到日志文件有需要就抽空清理失效鏈接。6.4 移動(dòng)端的適配與 PWA 離線緩存很多人以為導(dǎo)航頁(yè)只會(huì)在電腦上開但實(shí)際上手機(jī)瀏覽器打開導(dǎo)航頁(yè)的頻率也非常高。4.0510 主題在移動(dòng)端的適配比默認(rèn)主題更細(xì)致搜索框和 LOGO 在手機(jī)上縮小間距避免首屏全是空白卡片網(wǎng)格從 5 列自動(dòng)變成 2 列或 3 列導(dǎo)航分類的標(biāo)題在手機(jī)上固定定位滾動(dòng)時(shí)保持可見方便快速切換。如果想更進(jìn)一步可以給導(dǎo)航頁(yè)加一個(gè)簡(jiǎn)單的 PWA 離線緩存讓它在弱網(wǎng)狀態(tài)下也能打開。做法是在header.php里加 manifest 鏈接和 Service Worker 注冊(cè)代碼然后寫一個(gè)簡(jiǎn)單的sw.js文件緩存首頁(yè)和核心資源。不過(guò) PWA 對(duì) HTTPS 有硬性要求如果你只是內(nèi)網(wǎng) http 部署這部分可以跳過(guò)。7. 4.0510 主題的后續(xù)擴(kuò)展思路導(dǎo)航主題做到這一步功能和視覺(jué)都已經(jīng)比較完整了。如果你還想要更多我根據(jù)自己實(shí)際試過(guò)的方向列幾個(gè)可行的擴(kuò)展第一個(gè)是“快捷方式分類”加二級(jí)菜單。onenav 后臺(tái)默認(rèn)分類是扁平結(jié)構(gòu)但我的內(nèi)網(wǎng)系統(tǒng)里有很多子頁(yè)面比如路由器后臺(tái)下面還有交換機(jī)管理頁(yè)面。我通過(guò)在鏈接標(biāo)題里加入#分隔符再在前臺(tái)模板里做一個(gè)簡(jiǎn)單的分組渲染實(shí)現(xiàn)了類似二級(jí)菜單的效果。這個(gè)方法不需要改數(shù)據(jù)庫(kù)只是利用標(biāo)題規(guī)則和 CSS 技巧適合鏈接數(shù)量不多的時(shí)候用。第二個(gè)是“今日推薦”模塊。在主題首頁(yè)加一個(gè)獨(dú)立的區(qū)塊顯示最近添加的鏈接或者手動(dòng)置頂?shù)恼军c(diǎn)。實(shí)現(xiàn)方式很簡(jiǎn)單在主模板里額外加一個(gè)數(shù)據(jù)查詢調(diào)用 onenav 的鏈接模型按創(chuàng)建時(shí)間倒序取最近 5 條數(shù)據(jù)。這個(gè)小改動(dòng)能讓導(dǎo)航頁(yè)看起來(lái)更“活”而不是死板的一堆鏈接。第三個(gè)是“團(tuán)隊(duì)共享”場(chǎng)景的權(quán)限細(xì)分。如果你是把導(dǎo)航頁(yè)給整個(gè)小組用可能希望不同人看到不同分類。onenav 的用戶體系默認(rèn)比較簡(jiǎn)單但可以通過(guò)外部認(rèn)證或分組插件擴(kuò)展。我目前是直接把導(dǎo)航頁(yè)設(shè)為公開所有成員都能看能點(diǎn)但只有管理員能改鏈接和分類這樣能兼顧開放和穩(wěn)定。第四個(gè)是接入瀏覽器的“新標(biāo)簽頁(yè)”功能。Chrome 和 Edge 都支持自定義新標(biāo)簽頁(yè)擴(kuò)展原理是讓新標(biāo)簽頁(yè)直接 iframe 內(nèi)嵌你的導(dǎo)航頁(yè)地址。這樣瀏覽器一打開新標(biāo)簽頁(yè)就是你自己的導(dǎo)航站體驗(yàn)和設(shè)置主頁(yè)一樣順滑。如果你用的是 Firefox也可以通過(guò)插件實(shí)現(xiàn)類似效果。8. 最后分享兩個(gè)小技巧一是主題文件改完后“強(qiáng)制刷新”不一定能立即看到效果。onenav 在某些版本會(huì)啟用服務(wù)端頁(yè)面緩存直接刷新瀏覽器可能還是舊頁(yè)面。需要在后臺(tái)的“緩存管理”里清一下緩存再刷新一次。這個(gè)坑我踩過(guò)好幾次后來(lái)干脆養(yǎng)成“改完主題先清緩存再看效果”的習(xí)慣。二是如果你也想用這套“卡片式導(dǎo)航”的思路去改其他 PHP 導(dǎo)航程序上面的 CSS Grid 布局、圖標(biāo)三級(jí)回退、搜索框整合方案基本都是通用的改改模板變量名就能復(fù)用。我每次給別人推薦導(dǎo)航頁(yè)方案時(shí)都會(huì)說(shuō)一句話工具很多能按自己工作流定制的才叫好用。上面的部署、主題改造和運(yùn)維經(jīng)驗(yàn)基本覆蓋了從零到上線再到日常維護(hù)的完整鏈路。你可以照著步驟先搭一個(gè) demo再根據(jù)自己的實(shí)際習(xí)慣去調(diào)整分類和配色慢慢就會(huì)找到最適合自己使用節(jié)奏的那套導(dǎo)航方案。本文還有配套的精品資源點(diǎn)擊獲取