---
title: Onboarding 登录引导
description: 从登录、工作区、偏好到系统权限的五步首启引导
category: TemplateApp
status: beta
since: 0.6.0
tags: [template, onboarding, sign-in, setup, permissions]
syncStatus: reviewed
verified: false
---

## 用法

### 首启引导
:::TuffDemoWrapper{demo="TemplateOnboardingDemo" code-lang="vue" description="「看一遍流程」自动走完前三步并停在权限页，授权只能由你点击。登录与权限均为模拟。"}
---
code: |
  <script setup lang="ts">
  import { computed, reactive, ref } from 'vue'
  import TemplateFrame from './TemplateFrame.vue'

  const step = ref(0)
  const entered = ref(false)
  const perms = reactive({ files: 'unchecked', accessibility: 'unchecked', screen: 'unchecked' })

  // TxBorderBeam 默认按深色背景调色，auto 读的是系统而不是站点：显式传站点主题
  const colorMode = useColorMode()
  const beamTheme = computed(() => (colorMode.value === 'dark' ? 'dark' : 'light'))

  // 入场特效挂载即播，所以等舞台进入视口再挂载
  function onEnter() {
    entered.value = true
  }

  // 授权只由读者的点击触发；等待时长代替系统弹窗
  function grant(key: keyof typeof perms) {
    perms[key] = 'pending'
    setTimeout(() => {
      perms[key] = 'granted'
    }, 1200)
  }
  </script>

  <template>
    <TemplateFrame title="首启引导" :height="560" @enter="onEnter">
      <template #default="{ width }">
        <div class="onb" :class="{ 'is-narrow': width > 0 && width < 640 }">
          <aside class="onb__rail">
            <TxTuffLogoStroke v-if="entered" :size="56" mode="once" />
            <TxKeyframeStrokeText v-if="entered" text="欢迎来到 Tuff" :font-size="24" fill-color="var(--tx-text-color-primary)" />
            <TxSteps direction="vertical" size="small" :active="step">
              <!-- TxSteps 没有 emit：回退由宿主在原生 click 里判断 -->
              <TxStep v-for="(item, i) in steps" :key="item.key" :step="i" :title="item.title" :clickable="i < step" @click="i < step && (step = i)" />
            </TxSteps>
          </aside>

          <main class="onb__main">
            <TxProgressBar :percentage="(step + 1) * 20" height="4px" aria-label="引导进度" />
            <TxTransition preset="slide-fade" :appear="false">
              <section v-if="step === 0" key="signin">
                <TxBorderBeam size="sm" :theme="beamTheme" :active="!reducedMotion">
                  <TxButton block size="lg" :loading="pending === 'passkey'" @click="signIn('passkey')">
                    Passkey 登录
                  </TxButton>
                </TxBorderBeam>
                <TxForm :model="form" :rules="rules" label-position="top" @submit="sendMagicLink">
                  <TxFormItem label="邮箱" prop="email">
                    <template #default="{ id }">
                      <TxInput :id="id" v-model="form.email" type="email" />
                    </template>
                  </TxFormItem>
                  <TxButton native-type="submit" variant="primary" block>使用邮箱继续</TxButton>
                </TxForm>
              </section>
              <section v-else-if="step === 3" key="perms">
                <TxStatusBadge :text="statusText(perms.files)" :status="statusTone(perms.files)" size="sm" />
                <TxButton size="sm" :loading="perms.files === 'pending'" @click="grant('files')">允许访问</TxButton>
              </section>
              <!-- 工作区、偏好、完成三步从略 -->
            </TxTransition>
            <footer class="onb__footer">
              <TxButton variant="ghost" :disabled="step === 0" @click="step--">上一步</TxButton>
              <TxButton variant="primary" :disabled="!canContinue" @click="step++">继续</TxButton>
            </footer>
          </main>
        </div>
      </template>
    </TemplateFrame>
  </template>

  <style scoped>
  .onb {
    display: grid;
    grid-template-columns: 264px minmax(0, 1fr);
    height: 100%;
  }

  .onb.is-narrow {
    grid-template-columns: minmax(0, 1fr);
  }
  </style>
---
:::

## 概述

Tuff 桌面版的首启引导：每一步都是模拟，不发请求，也不申请真实权限。

- 登录方式与 Tuff 一致：Passkey、GitHub、LINUX DO 与邮箱 Magic Link，没有密码框；「离线继续」跳过工作区一步。
- 「继续」只在本步满足条件时可用，旁边写明还差什么；「上一步」与已完成的步骤都能回退，换步时焦点移到新步骤标题。
- 呼出快捷键可录制：组合须含 ⌘、⌃ 或 ⌥，Esc 取消；⌘W、⌘T 这类浏览器保留的组合会被拒绝。
- 每项权限都要你点「允许访问」；屏幕录制第一次被拒，行内给出「前往系统设置」。
- 进入视口时只播入场；「看一遍流程」自动走到权限页停下；点击或按键即停止；减少动态效果时直接跳到权限页。
- 完成页里按下呼出快捷键即唤起迷你 CoreBox；≥ 1200px 右侧出现实时预览，窄屏（< 640px）品牌栏收成顶部一行。

## 自定义

- 接真实登录时，把 `signIn()` 里的计时器换成 OAuth 跳转或 WebAuthn 调用；不要加密码框，Tuff 本就没有密码登录。
- 接真实权限时，状态从系统读取，「允许访问」触发系统弹窗后重新检查；授权只由用户点击触发。
- 入场特效（TxTuffLogoStroke 的 `once`、TxKeyframeStrokeText、TxGlowText 的 `:repeat="false"`）挂载即播：等可见时再挂载，换 `key` 重播。
- TxBorderBeam 的旋转家族（`sm`、`md`、`line`）没有减弱动态效果兜底，此时传 `:active="false"`；`theme` 默认 `dark`，`auto` 跟随系统而非站点，要显式传站点主题。
- TxSteps 没有 emit：回退要在 TxStep 上挂原生 `@click`，并只给已完成的步骤 `clickable`。

## 相关组件

| 区域 | 组件 | 作用 |
|---|---|---|
| 品牌栏 | [TxTuffLogoStroke](/docs/dev/components/tuff-logo-stroke)、[TxKeyframeStrokeText](/docs/dev/components/keyframe-stroke-text)、[TxGlowText](/docs/dev/components/glow-text) | 入场描边与扫光 |
| 步骤 | [TxSteps / TxStep](/docs/dev/components/steps)、[TxProgressBar](/docs/dev/components/progress-bar) | 五步进度，可回退 |
| 登录 | [TxBorderBeam](/docs/dev/components/border-beam)、[TxButton](/docs/dev/components/button)、[TxBadge](/docs/dev/components/badge)、[TxForm / TxFormItem](/docs/dev/components/form)、[TxInput](/docs/dev/components/input) | 四种登录方式与离线继续 |
| 工作区 | [TxRadioGroup / TxRadio](/docs/dev/components/radio)、[TxFlatRadio](/docs/dev/components/flat-radio)、[TxAvatar](/docs/dev/components/avatar)、[TxTagInput](/docs/dev/components/tag-input)、[TxCard](/docs/dev/components/card) | 创建个人空间或接受邀请 |
| 偏好 | [TxKbd](/docs/dev/components/kbd)、[TxGradientBorder](/docs/dev/components/gradient-border)、[TxFlatRadio](/docs/dev/components/flat-radio)、[TxRadioGroup / TxRadio](/docs/dev/components/radio)、[TuffSwitch](/docs/dev/components/switch) | 快捷键、主题与启动选项 |
| 权限 | [TxIconChip](/docs/dev/components/icon-chip)、[TxTag](/docs/dev/components/tag)、[TxStatusBadge](/docs/dev/components/status-badge)、[TxProgressBar](/docs/dev/components/progress-bar) | 三项权限及其状态 |
| 完成 | [TxKeyframeStrokeText](/docs/dev/components/keyframe-stroke-text)、[TxGlowText](/docs/dev/components/glow-text)、[TxKbd](/docs/dev/components/kbd)、[TxBorderBeam](/docs/dev/components/border-beam)、[TxGlassSurface](/docs/dev/components/glass-surface)、[TxCardItem](/docs/dev/components/card-item) | 试按快捷键与设置摘要 |
| 切换与反馈 | [TxTransition](/docs/dev/components/transition)、[TxToastPanel](/docs/dev/components/toast-panel) | 步骤过渡与结果提示 |
| 实时预览（宽屏） | [TxGlassSurface](/docs/dev/components/glass-surface)、[TxStatusBadge](/docs/dev/components/status-badge) | 实时预览设置效果 |
