---
title: Docs 知识库
description: 带目录树、本页目录与 ⌘K 检索的帮助中心阅读器
category: TemplateContent
status: beta
since: 0.6.0
tags: [template, docs, markdown, outline, search]
syncStatus: reviewed
verified: false
---

## 用法

### 三栏知识库
:::TuffDemoWrapper{demo="TemplateDocsDemo" code-lang="vue" description="进入视口后文章自动滚到两个章节，你一动就停下；⌘K 搜索文章与章节。"}
---
code: |
  <script setup lang="ts">
  import { useIndicatorBox } from '@talex-touch/tuffex/sidebar-nav'
  import { computed, ref } from 'vue'
  import TemplateFrame from './TemplateFrame.vue'

  // 大纲从 Markdown 源码里解析，按顺序对应渲染出来的 h2 / h3：
  // TxMarkdownView 的标题没有 id，也不能加（文档页会收集带 id 的标题并滚动整页）
  const outline = computed(() => parseHeadings(article.value.body))

  // 只滚文章自己的滚动容器，从不 scrollIntoView
  function scrollToHeading(index: number) {
    scroller.value?.scrollTo({ top: offsets[index] - 12, behavior: 'smooth' })
  }

  // 正文里的链接是真 <a>：在外层委托拦截，#kb:<id> 打开站内文章
  function onBodyClick(event: MouseEvent) {
    const link = (event.target as Element).closest('a')
    if (!link)
      return
    event.preventDefault()
    const href = link.getAttribute('href') ?? ''
    if (href.startsWith('#kb:'))
      openArticle(href.slice(4))
  }

  // 本页目录的滑动标记：和 TxSidebarNav 高亮用同一套测量
  const { box } = useIndicatorBox({ container: outlineList, target: () => items[active.value] })
  </script>

  <template>
    <TemplateFrame title="三栏知识库" :height="580" @enter="startTour">
      <aside>
        <TxSearchInput v-model="filter" placeholder="筛选目录" />
        <TxTree :nodes="tree" :model-value="articleId" v-model:expanded-keys="open" :filter-text="filter" @select="onTreeSelect" />
      </aside>

      <div ref="scroller" class="article" tabindex="0" @scroll.passive="syncActive">
        <TxBreadcrumb :items="crumbs" @click="onCrumb" />
        <div @click="onBodyClick" @auxclick="onBodyAuxClick">
          <TxMarkdownView :content="article.body" />
        </div>
        <TxFlatRadio :model-value="vote" size="sm" @update:model-value="onVote">
          <TxFlatRadioItem value="up" icon="i-carbon-thumbs-up" label="有帮助" />
          <TxFlatRadioItem value="down" icon="i-carbon-thumbs-down" label="没帮助" />
        </TxFlatRadio>
        <TxCardItem clickable role="link" :title="next.title" subtitle="下一篇" @click="openArticle(next.id)" />
      </div>

      <nav aria-label="本页目录">
        <button v-for="(heading, index) in outline" :key="index" :aria-current="index === active ? 'true' : undefined" @click="scrollToHeading(index)">
          {{ heading.text }}
        </button>
      </nav>

      <!-- ⌘K 绑在模板根节点上，面板关闭后把焦点还给搜索按钮 -->
      <TxCommandPalette v-model="paletteOpen" :commands="commands" placeholder="搜索文章或章节…" @select="onCommand" @close="focusSearch" />
    </TemplateFrame>
  </template>
---
:::

## 概述

Tuff 的三栏帮助中心；主推文章「插件权限说明」取自真实的权限注册表，其余为示例内容。

- 首次进入视口时，文章自动滚到「风险等级」与「安装时的授权选择」后停下；点击、按键、滚轮或触摸即结束，减少动态效果时直接停在后一节。
- 演示只滚文章自己的滚动容器，不动页面，也不移动焦点。
- 本页目录从 Markdown 源码解析，按顺序对应渲染出的标题；TxMarkdownView 的标题没有 id，模板也不加。
- 点目录项平滑滚到该节并保持高亮，直到你自己滚动文章。
- 正文链接在外层统一拦截：`#kb:` 链接在模板内打开文章；外链、中键与 ⌘ 点击只提示宿主会打开什么。
- 栏内（640–959px）本页目录收进工具行的下拉菜单；展开后为三栏；窄于 640px 时目录树变为左侧滑出的面板。
- ⌘K 绑在模板根节点，只在焦点位于模板内时生效；关闭面板后焦点回到搜索按钮。

## 自定义

- 接入真实文档时，大纲继续从源码解析；改用会生成标题 id 的渲染器前，先确认页面上没有脚本按 id 滚动整页。
- 需要代码高亮时，整篇改用 TxStreamMarkdown（非流式）；正文里混用多个渲染器会让标题序号对不上。
- 文章多时，⌘K 改为按输入远程检索，章节只收录二级标题。
- 反馈接口记录文章 id、所选原因与文章版本号。

## 相关组件

| 区域 | 组件 | 作用 |
|---|---|---|
| 顶栏 | [TxKbd](/docs/dev/components/kbd)、[TxCommandPalette](/docs/dev/components/command-palette) | ⌘K 搜索文章与章节 |
| 目录 | [TxSearchInput](/docs/dev/components/search-input)、[TxTree](/docs/dev/components/tree)、[TxBadge](/docs/dev/components/badge) | 可筛选、可折叠的目录树 |
| 工具行 | [TxBreadcrumb](/docs/dev/components/breadcrumb)、[TxDropdownMenu](/docs/dev/components/dropdown-menu)、[TxProgressBar](/docs/dev/components/progress-bar) | 面包屑、目录与阅读进度 |
| 正文 | [TxMarkdownView](/docs/dev/components/markdown-view)、[TxAvatar](/docs/dev/components/avatar) | 正文、贡献者与更新时间 |
| 文章反馈 | [TxFlatRadio](/docs/dev/components/flat-radio)、[TxCheckbox](/docs/dev/components/checkbox)、[TxTextarea](/docs/dev/components/textarea)、[TxButton](/docs/dev/components/button) | 有帮助 / 没帮助与原因 |
| 上一篇 / 下一篇、相关文章 | [TxCardItem](/docs/dev/components/card-item) | 相邻与相关文章 |
| 本页目录（展开后） | 手写列表 + `useIndicatorBox` | 跟随滚动高亮当前章节 |
| 结果提示 | [TxToastPanel](/docs/dev/components/toast-panel) | 外链、编辑与反馈的结果 |
