@incremark/vue
v1.0.2
Published
High-performance streaming markdown renderer for Vue 3 ecosystem.
Maintainers
Readme
@incremark/vue
Incremark 的 Vue 3 集成库。
🇨🇳 中文 | 🇺🇸 English
特性
- 📦 开箱即用 - 提供
useIncremarkcomposable 和<Incremark>组件 - ⌨️ 打字机效果 - 内置
useBlockTransformer实现逐字符显示 - 🎨 可定制 - 支持自定义渲染组件
- ⚡ 高性能 - 使用
shallowRef和markRaw优化性能 - 🔧 DevTools - 内置开发者工具
安装
pnpm add @incremark/vue @incremark/theme快速开始
<script setup>
import { ref } from 'vue'
import { IncremarkContent } from '@incremark/vue'
import '@incremark/theme/styles.css'
const content = ref('')
const isFinished = ref(false)
async function handleStream(stream) {
for await (const chunk of stream) {
content.value += chunk
}
isFinished.value = true
}
</script>
<template>
<button @click="handleStream">开始</button>
<IncremarkContent :content="content" :is-finished="isFinished" />
</template>API
useIncremark(options)
核心 composable。
返回值:
| 属性 | 类型 | 说明 |
|------|------|------|
| markdown | Ref<string> | 完整 Markdown |
| blocks | ComputedRef<Block[]> | 所有块 |
| completedBlocks | ShallowRef<Block[]> | 已完成块 |
| pendingBlocks | ShallowRef<Block[]> | 待处理块 |
| isLoading | Ref<boolean> | 是否正在加载 |
| append | Function | 追加内容 |
| finalize | Function | 完成解析 |
| reset | Function | 重置状态 |
| render | Function | 一次性渲染(reset + append + finalize) |
useBlockTransformer(sourceBlocks, options)
打字机效果 composable。作为解析器和渲染器之间的中间层,控制内容的逐步显示。
参数:
| 参数 | 类型 | 说明 |
|------|------|------|
| sourceBlocks | Ref<SourceBlock[]> | 源 blocks(通常来自 completedBlocks) |
| options.charsPerTick | number | 每次显示的字符数(默认:2) |
| options.tickInterval | number | 每次显示的间隔时间 ms(默认:50) |
| options.plugins | TransformerPlugin[] | 插件列表(用于特殊块的处理) |
返回值:
| 属性 | 类型 | 说明 |
|------|------|------|
| displayBlocks | ComputedRef<DisplayBlock[]> | 用于渲染的 blocks |
| isProcessing | ComputedRef<boolean> | 是否正在处理中 |
| skip | Function | 跳过动画,立即显示全部内容 |
| reset | Function | 重置状态 |
| setOptions | Function | 动态更新配置 |
使用示例:
<script setup>
import { computed, ref, watch } from 'vue'
import { useIncremark, useBlockTransformer, Incremark, defaultPlugins } from '@incremark/vue'
const { completedBlocks, append, finalize, reset: resetParser } = useIncremark()
// 配置打字机速度
const typewriterSpeed = ref(2)
const typewriterInterval = ref(50)
// 转换为 SourceBlock 格式
const sourceBlocks = computed(() =>
completedBlocks.value.map(block => ({
id: block.id,
node: block.node,
status: block.status
}))
)
// 使用 BlockTransformer
const {
displayBlocks,
isProcessing,
skip,
reset: resetTransformer,
setOptions
} = useBlockTransformer(sourceBlocks, {
charsPerTick: typewriterSpeed.value,
tickInterval: typewriterInterval.value,
plugins: defaultPlugins
})
// 监听配置变化
watch([typewriterSpeed, typewriterInterval], ([speed, interval]) => {
setOptions({ charsPerTick: speed, tickInterval: interval })
})
// 转换为渲染格式
const renderBlocks = computed(() =>
displayBlocks.value.map(db => ({
id: db.id,
stableId: db.id,
node: db.displayNode,
status: db.isDisplayComplete ? 'completed' : 'pending'
}))
)
</script>
<template>
<Incremark :blocks="renderBlocks" />
<button v-if="isProcessing" @click="skip">跳过</button>
</template>useDevTools(incremark)
启用 DevTools。
const incremark = useIncremark()
useDevTools(incremark)<Incremark>
渲染组件。
<Incremark
:blocks="blocks"
:components="{ heading: MyHeading }"
:show-block-status="true"
/>Props:
| Prop | 类型 | 说明 |
|------|------|------|
| blocks | Block[] | 要渲染的 blocks |
| components | object | 自定义组件映射 |
| showBlockStatus | boolean | 是否显示块状态(pending/completed) |
自定义组件
<script setup>
import { useIncremark, Incremark } from '@incremark/vue'
import MyCode from './MyCode.vue'
const { blocks } = useIncremark()
</script>
<template>
<Incremark
:blocks="blocks"
:components="{ code: MyCode }"
/>
</template>数学公式支持
pnpm add micromark-extension-math mdast-util-math katex<script setup>
import { useIncremark } from '@incremark/vue'
import { math } from 'micromark-extension-math'
import { mathFromMarkdown } from 'mdast-util-math'
import 'katex/dist/katex.min.css'
const { blocks } = useIncremark({
extensions: [math()],
mdastExtensions: [mathFromMarkdown()]
})
</script>插件系统
BlockTransformer 支持插件来处理特殊类型的块:
import {
defaultPlugins,
codeBlockPlugin,
imagePlugin,
mermaidPlugin,
mathPlugin,
thematicBreakPlugin,
createPlugin
} from '@incremark/vue'
// 使用默认插件集
const { displayBlocks } = useBlockTransformer(sourceBlocks, {
plugins: defaultPlugins
})
// 或自定义插件
const myPlugin = createPlugin({
name: 'my-plugin',
match: (node) => node.type === 'myType',
transform: (node) => ({ displayNode: node, isComplete: true })
})内置插件:
| 插件 | 说明 |
|------|------|
| codeBlockPlugin | 代码块整体显示 |
| imagePlugin | 图片整体显示 |
| mermaidPlugin | Mermaid 图表整体显示 |
| mathPlugin | 数学公式整体显示 |
| thematicBreakPlugin | 分隔线整体显示 |
AutoScrollContainer
自动滚动容器组件,适用于流式内容场景:
<script setup>
import { ref } from 'vue'
import { AutoScrollContainer, Incremark } from '@incremark/vue'
const scrollRef = ref()
const autoScrollEnabled = ref(true)
</script>
<template>
<AutoScrollContainer
ref="scrollRef"
:enabled="autoScrollEnabled"
:threshold="50"
behavior="smooth"
>
<Incremark :blocks="blocks" />
</AutoScrollContainer>
<!-- 显示滚动状态 -->
<span v-if="scrollRef?.isUserScrolledUp?.()">
用户已暂停自动滚动
</span>
<!-- 强制滚动到底部 -->
<button @click="scrollRef?.scrollToBottom()">
滚动到底部
</button>
</template>Props:
| Prop | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| enabled | boolean | true | 是否启用自动滚动 |
| threshold | number | 50 | 触发自动滚动的底部阈值(像素) |
| behavior | ScrollBehavior | 'instant' | 滚动行为 |
暴露的方法(通过 ref):
| 方法 | 说明 |
|------|------|
| scrollToBottom() | 强制滚动到底部 |
| isUserScrolledUp() | 返回用户是否手动向上滚动了 |
| container | 容器 DOM 元素引用 |
License
MIT
