2. Docsify の起動順とサイトナビのマウント
英語用の HTML シェルは site/index.html,日本語用は site/ja/index.html です。各シェルの body には,主要な要素として Docsify のマウント先である #app,言語別設定を格納する window.RT,実行に必要なスクリプトを記述します。サイトナビゲーションのマークアップは,HTML シェルには含めません。
<body class="loading">
<div id="app"></div>
<script>
window.RT = {
// 言語,公開パス,表示文字列などの設定
};
</script>
<script src="/ai/app.js"></script>
<script src="/ai/vendor/docsify/docsify.min.js"></script>
<script src="/ai/vendor/docsify/search.min.js"></script>
</body>読み込み順では,app.js を Docsify 本体より前に配置する必要があります。Docsify 5 は初期化時に window.$docsify を参照するため,この設定を Docsify 本体より後に定義すると,サイドバーやプラグインが有効になりません。
$docsify の設定範囲
app.js が定義する設定のうち,サイトナビゲーションに関係する部分を次に示します。
window.$docsify = {
name: "Real Terms",
nameLink: RT.publicBase + "#/",
basePath: RT.contentBase,
homepage: "README.md",
loadSidebar: true,
relativePath: false,
auto2top: true,
alias: docsifyAliases,
search: {
placeholder: S.searchPlaceholder,
noData: S.searchNoData,
},
// plugins などは省略
};loadNavbar は指定していないため,既定値の無効状態になります。search オブジェクトは表示文字列を設定し,検索 UI は search.min.js がサイドバーへ挿入します。サイトナビゲーションには検索 UI を配置しません。
プラグイン siteChrome
Docsify の plugins 配列では,siteChrome を先頭に登録します。このプラグインは三つのフックを使用します。
function siteChrome(hook) {
var syncNavAfterRoute;
hook.afterEach(function (html, next) {
// Docsify #y() scrollIntoViews the first heading unless it already
// has tabindex. Keep preventScroll focus, skip the 64px nudge.
html = html.replace(/<(h[1-6])(\s[^>]*)?>/gi, function (match, tag, attrs) {
attrs = attrs || "";
if (/\btabindex\s*=/i.test(attrs)) {
return match;
}
return "<" + tag + ' tabindex="-1"' + attrs + ">";
});
next(html);
});
hook.ready(function () {
ensureSiteNav();
syncNavAfterRoute = setupSiteNavScrollReveal();
});
hook.doneEach(function () {
if (syncNavAfterRoute) {
syncNavAfterRoute();
}
});
}afterEach
Docsify が生成した本文 HTML の見出しにtabindex="-1"を追加します。Docsify は先頭見出しを表示領域へ移動しますが,あらかじめtabindexがある場合はスクロールを伴わないフォーカス処理になります。これにより,先頭見出しが 64px の固定ナビゲーションの背後へ移動する現象を防ぎます。ready
Docsify の初期化完了後に一度だけensureSiteNav()を呼び出し,続けてスクロールに応じた表示制御を登録します。doneEach
各ルートの描画完了後に,サイトナビゲーションを表示状態へ戻します。詳細は第4章で説明します。
#app の外部への挿入
ensureSiteNav() は,既存の .eg-site-nav があればその要素を返します。存在しない場合は header を生成し,document.body の先頭へ挿入します。
document.body.insertBefore(header, document.body.firstChild);Docsify はルートが変わるたびに,自身のレンダリング領域を更新します。サイトナビゲーションを #app 内へ配置すると,再描画によって要素が失われるか,メニューの開閉状態やスクロールに応じた表示状態を維持できません。document.body の直下へ配置することで,サイトナビゲーションを Docsify の再描画から分離できます。
ここまでの起動順を図にすると,次のようになります。
次章では,生成した header の DOM 構造と,各要素の役割を説明します。