Markdown で Vue を使う
VitePress では、各 Markdown ファイルは HTML にコンパイルされ、Vue 単一ファイルコンポーネントとして処理されます。つまり、ダイナミックなテンプレート、Vue コンポーネントの使用、<script>
タグを追加することによる任意のページ内 Vue コンポーネントロジックなど、Markdown 内で Vue のあらゆる機能を使用できます。
VitePress が Vue のコンパイラーを活用して、Markdown コンテンツの純粋に静的な部分を自動的に検出して最適化することに注意してください。静的なコンテンツは、初期訪問時のページ JavaScript ペイロードから削除され、単一のプレースホルダーノードに最適化されます。また、クライアントサイドのハイドレーション中もスキップされます。つまり、任意のページで動的な部分に対してのみコストがかかります。
SSR互換性
すべての Vue の使用は SSR と互換性がある必要があります。詳細と一般的な回避策については、SSR互換性を参照してください。
テンプレート
補間
各 Markdown ファイルは最初に HTML にコンパイルされ、Vue コンポーネントとして Vite プロセスパイプラインに渡されます。つまり、テキストで Vue スタイルの補間を使用できます
入力
{{ 1 + 1 }}
出力
2
ディレクティブ
ディレクティブも機能します(設計上、生の HTML も Markdown で有効であることに注意してください)
入力
<span v-for="i in 3">{{ i }}</span>
出力
1 2 3
<script>
と <style>
Markdown ファイルのルートレベルの <script>
および <style>
タグは、<script setup>
、<style module>
など、Vue SFC と同様に機能します。ここでの主な違いは、<template>
タグがないことです。他のすべてのルートレベルのコンテンツは Markdown です。また、すべてのタグはフロントマターの**後**に配置する必要があることに注意してください。
---
hello: world
---
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
## Markdown Content
The count is: {{ count }}
<button :class="$style.button" @click="count++">Increment</button>
<style module>
.button {
color: red;
font-weight: bold;
}
</style>
Markdown で <style scoped>
を避ける
Markdown で使用する場合、<style scoped>
では、現在のページのすべての要素に特別な属性を追加する必要があるため、ページサイズが大幅に膨らみます。ページでローカルスコープのスタイルが必要な場合は、<style module>
が推奨されます。
また、現在のページのメタデータへのアクセスを提供する useData
ヘルパーなどの VitePress のランタイム API にもアクセスできます
入力
<script setup>
import { useData } from 'vitepress'
const { page } = useData()
</script>
<pre>{{ page }}</pre>
出力
{
"path": "/using-vue.html",
"title": "Using Vue in Markdown",
"frontmatter": {},
...
}
コンポーネントの使用
Markdown ファイルで Vue コンポーネントを直接インポートして使用できます。
Markdown でのインポート
コンポーネントがいくつかのページでのみ使用される場合は、使用する場所で明示的にインポートすることをお勧めします。これにより、適切にコード分割され、関連するページが表示されたときにのみロードされるようになります
<script setup>
import CustomComponent from '../components/CustomComponent.vue'
</script>
# Docs
This is a .md using a custom component
<CustomComponent />
## More docs
...
コンポーネントのグローバル登録
コンポーネントがほとんどのページで使用される場合は、Vue アプリインスタンスをカスタマイズすることでグローバルに登録できます。例については、デフォルトテーマの拡張の関連セクションを参照してください。
重要
カスタムコンポーネントの名前には、ハイフンが含まれているか、PascalCase になっていることを確認してください。そうしないと、インライン要素として扱われ、<p>
タグで囲まれます。これにより、<p>
はブロック要素を内部に配置することを許可しないため、ハイドレーションの不一致が発生します。
ヘッダーでのコンポーネントの使用 ⚡
ヘッダーで Vue コンポーネントを使用できますが、次の構文の違いに注意してください
Markdown | 出力 HTML | 解析済みヘッダー |
---|---|---|
| <h1>テキスト <Tag/></h1> | テキスト |
| <h1>テキスト <code><Tag/></code></h1> | テキスト <Tag/> |
<code>
で囲まれた HTML はそのまま表示されます。**囲まれていない** HTML のみが Vue によって解析されます。
ヒント
出力 HTML は Markdown-it によって実現され、解析されたヘッダーは VitePress によって処理されます(サイドバーとドキュメントタイトルの両方に使用されます)。
エスケープ
Vue の補間をエスケープするには、v-pre
ディレクティブを持つ <span>
または他の要素で囲みます
入力
This <span v-pre>{{ will be displayed as-is }}</span>
出力
この {{ はそのまま表示されます }}
または、段落全体を v-pre
カスタムコンテナで囲むこともできます
::: v-pre
{{ This will be displayed as-is }}
:::
出力
{{ これはそのまま表示されます }}
コードブロックでのエスケープ解除
デフォルトでは、すべてのフェンス付きコードブロックは自動的に v-pre
でラップされるため、内部で Vue 構文が処理されることはありません。フェンス内で Vue スタイルの補間を有効にするには、js-vue
など、言語に -vue
サフィックスを追加できます
入力
```js-vue
Hello {{ 1 + 1 }}
```
出力
Hello 2
これにより、特定のトークンが正しく構文強調表示されない場合があります。
CSSプリプロセッサの使用
VitePress には、CSS プリプロセッサ: .scss
、.sass
、.less
、.styl
、.stylus
ファイルの 組み込みサポートがあります。Vite 固有のプラグインをインストールする必要はありませんが、対応するプリプロセッサ自体をインストールする必要があります
# .scss and .sass
npm install -D sass
# .less
npm install -D less
# .styl and .stylus
npm install -D stylus
次に、Markdown およびテーマコンポーネントで以下を使用できます
<style lang="sass">
.title
font-size: 20px
</style>
テレポーテーションの使用
VitePress は現在、ボディへのテレポーテーションのみを SSG サポートしています。他のターゲットについては、組み込みの <ClientOnly>
コンポーネントでラップするか、postRender
フックを使用して、最終的なページ HTML の正しい場所にテレポーテーションマークアップを注入できます。
詳細
<script setup lang="ts">
import { ref } from 'vue'
const showModal = ref(false)
</script>
<template>
<button class="modal-button" @click="showModal = true">Show Modal</button>
<Teleport to="body">
<Transition name="modal">
<div v-show="showModal" class="modal-mask">
<div class="modal-container">
<p>Hello from the modal!</p>
<div class="model-footer">
<button class="modal-button" @click="showModal = false">
Close
</button>
</div>
</div>
</div>
</Transition>
</Teleport>
</template>
<style scoped>
.modal-mask {
position: fixed;
z-index: 200;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.3s ease;
}
.modal-container {
width: 300px;
margin: auto;
padding: 20px 30px;
background-color: var(--vp-c-bg);
border-radius: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
transition: all 0.3s ease;
}
.model-footer {
margin-top: 8px;
text-align: right;
}
.modal-button {
padding: 4px 8px;
border-radius: 4px;
border-color: var(--vp-button-alt-border);
color: var(--vp-button-alt-text);
background-color: var(--vp-button-alt-bg);
}
.modal-button:hover {
border-color: var(--vp-button-alt-hover-border);
color: var(--vp-button-alt-hover-text);
background-color: var(--vp-button-alt-hover-bg);
}
.modal-enter-from,
.modal-leave-to {
opacity: 0;
}
.modal-enter-from .modal-container,
.modal-leave-to .modal-container {
transform: scale(1.1);
}
</style>
<ClientOnly>
<Teleport to="#modal">
<div>
// ...
</div>
</Teleport>
</ClientOnly>