Skip to content

路由与通用组件封装(一) ​

本页对应 路由与通用组件封装,共 7 段视频,约 1 小时 4 分。

学习目标 ​

  • 能够按照“一级路由 / 二级路由”的设计规则,在 router/index.ts 中为登录页配置懒加载路由,并在 App.vue 中放置路由出口,通过访问 /login 验证页面正常渲染。
  • 能够安装并配置 unplugin-vue-components 与 Vant 解析器,实现 Vant 组件与 components 目录下组件的自动注册,并通过 dts: false、importStyle: false 消除类型声明文件与样式重复引入的问题,且能在不写 import 的情况下正常使用按钮、复选框组件。
  • 能够基于 Vant 导航组件二次封装 cp-nav-bar,通过 fixed、left-arrow、title、right-text 属性搭建结构,并使用 :deep() 深度选择器将左侧箭头改为黑色 18px、标题改为 15px,使样式与设计稿一致。
  • 能够使用 defineProps 声明可选的 title、rightText 属性实现标题与右侧文字的动态设置,并在点击右侧文字时通过 defineEmits 触发 click-right 自定义事件(无文字时不触发),在父组件中验证事件回调被正确执行。
  • 能够利用 history.state.back 判断是否存在访问历史,在 click-left 回调中分别执行 router.back() 或 router.push('/'),并分别在“有历史”与“直接访问”两种场景下验证回退结果。
  • 能够通过 declare module 'vue' 扩展 GlobalComponents 并用 typeof 组件 为全局组件补充类型,使自动注册的 cp-nav-bar 获得属性提示与类型校验;同时能引入全局重置样式、用 CSS 变量定制 Vant 表单项间距/复选框尺寸/按钮字号,并清理 App.vue 多余容器、跳转链接及 router/index.ts 中的调试打印。

知识点 ​

先明确:优医问诊的路由规则怎么设计 ​

为什么需要:进入页面开发前,必须先知道“哪些页面整页切换、哪些页面只切换局部”。否则组件放哪、路由出口放哪都会乱。
怎么想:登录页→个人中心,是整页替换,设计成一级路由;个人中心→首页时,底部 TabBar 不动,只换上方内容,设计成二级路由。于是形成“一级布局容器 + 二级内容页”的嵌套路由。
怎么做:按笔记中的路由规则表配置:登录页、结束问诊页等属于一级路由;布局容器是一级路由,里面承载首页、健康百科、消息通知、个人中心等二级路由。
易错点:不要把登录页塞进带 TabBar 的布局容器里;一级路由出口要放在 App.vue,二级路由出口要放在布局容器组件里。

登录页路由与路由出口 ​

为什么需要:只有组件没有路由,浏览器访问不到页面;只有路由没有出口,组件也不会显示。
怎么想:先在 views/login/index.vue 准备登录组件,再到 router/index.ts 增加 /login 规则,最后在 App.vue 放一级路由出口。
怎么做:

ts
// router/index.ts
{
  path: '/login',
  component: () => import('@/views/login/index.vue')
}
vue
<!-- App.vue -->
<template>
  <router-view />
</template>

调试时访问 /login,如果看不到页面,先检查 App.vue 是否还有旧测试代码、是否写了 router-view。
易错点:路由懒加载要写在 component 里;App.vue 是一级出口,不要误放到登录组件内部。

配置 Vant 组件自动注册 ​

为什么需要:每个 Vant 组件都手写 import 很繁琐。自动注册后,模板里可直接使用。
怎么想:用 unplugin-vue-components 插件,在 vite.config.ts 的 plugins 中启用,并配置 VantResolver。
怎么做:安装插件后配置解析器;再处理两个优化:importStyle: false 避免与 main.ts 中已导入的 Vant 样式重复;dts: false 避免自动生成重复类型声明文件。
调试过程:先手写导入按钮、复选框,页面正常;配置自动注册后删掉导入,页面仍正常。检查元素发现同一组件样式出现两份,开启 importStyle: false 后只剩一份;删除自动生成的 components.d.ts 后不再反复生成。
易错点:不是去 main.ts 做全局注册;插件配置在 vite.config.ts,不是 main.ts。

ts
// vite.config.ts 关键配置示意
Components({
  resolvers: [VantResolver()],
  importStyle: false,
  dts: false
})

封装 cp-nav-bar 的结构与样式 ​

为什么需要:多个页面都有顶部通栏,且样式接近,应封装成通用组件。
怎么想:基于 van-nav-bar 二次封装,结构用 Vant 属性实现:固定定位、左箭头、标题、右侧文字;再用深度选择器覆盖样式。
怎么做:在 components 下新建 cp-nav-bar.vue,模板使用 van-nav-bar,加上 fixed、left-arrow、title、right-text。样式覆盖左箭头颜色和字号、标题字号:

vue
<van-nav-bar fixed left-arrow title="登录" right-text="注册" />

<style scoped lang="scss">
:deep(.van-nav-bar__arrow) {
  color: var(--cp-text1);
  font-size: 18px;
}
:deep(.van-nav-bar__title) {
  font-size: 15px;
}
</style>

易错点:覆盖 Vant 内部样式要用 :deep();选择器要找对,箭头和标题分别是不同类名。

标题、右侧文字与右侧点击事件 ​

为什么需要:通用导航不能写死“登录/注册”,要由使用方动态传入;右侧文字点击后要能执行不同业务。
怎么想:标题和右侧文字用 props,都可选;右侧点击用 emit 抛出 click-right。
怎么做:

ts
const props = defineProps<{
  title?: string
  rightText?: string
}>()
const emit = defineEmits<{ (e: 'click-right'): void }>()

模板中绑定 :title="title"、:right-text="rightText",监听 @click-right="emit('click-right')"。调试时先打印,确认有右侧文字才触发;去掉文字后不触发,符合要求。
易错点:rightText 在模板属性中写 right-text;没有右侧文字时不要强行触发事件。

回退功能:判断 history.state.back ​

为什么需要:点击左箭头要能返回;若直接访问登录页,没有历史记录,不能盲目 back()。
怎么想:history.state.back 有值说明有历史,正常回退;没有则跳首页。
怎么做:

ts
const router = useRouter()
const onClickLeft = () => {
  if (history.state?.back) router.back()
  else router.push('/')
}

调试时直接访问 /login,back 为空,点击回首页;从 /home 跳登录后,back 有值,点击能回 /home。
易错点:加可选链,避免 history.state 为空报错。

给自动注册组件补类型 ​

为什么需要:自动注册组件不显式导入,默认类型可能是 unknown,没有属性提示和校验。
怎么想:在类型声明文件中扩展 Vue 的 GlobalComponents,用 typeof import(...)['default'] 取组件类型。
怎么做:

ts
declare module 'vue' {
  interface GlobalComponents {
    CpNavBar: typeof import('@/components/cp-nav-bar.vue')['default']
  }
}
export {}

配置后模板中组件变绿,写 right-text 有提示,传 number 会报错。
易错点:这是全局/自动注册组件的类型扩展;局部组件显式导入后通常可自动推导。

登录页布局、Vant 表单变量与清理代码 ​

为什么需要:业务开发前要先有稳定页面结构和全局样式。
怎么想:全局重置样式放 main.scss;登录页分头部、表单、底部;表单用 Vant,但间距、复选框大小、按钮文字大小用 CSS 变量覆盖。
怎么做:复制笔记中的全局重置样式;在 views/login/index.vue 搭结构;把 QQ 图标放入 assets;在 main.scss 覆盖 Vant 变量处补三个变量。清理 App.vue 中多余的 .app 容器和测试跳转链接,删除 router/index.ts 中多余的 import.meta 打印。
易错点:Vue3 的 app.mount('#app') 是把根组件插入 #app,不是像 Vue2 替换,所以不要再套一层多余容器。

本节要解决的问题 ​

转写稿里多次把 Vant 说成“w”,这里统一纠正为 Vant。本节的目标是:在登录页真正写业务之前,先配置 unplugin-vue-components,让 Vant 组件在模板里直接使用,不再每次手动 import。同时处理两个容易忽略的重复问题:样式重复引入、类型声明文件重复生成。

为什么需要组件自动注册 ​

为什么需要: 登录页会大量使用 Vant 的按钮、复选框、表单等组件。如果每用一个组件都先导入,代码会变得零碎。转写稿中先在 views/login/index.vue 里演示了手动写法:

vue
<script setup lang="ts">
import { Button as VanButton, Checkbox as VanCheckbox } from 'vant'
</script>

<template>
  <van-button>按钮</van-button>
  <van-checkbox>复选框</van-checkbox>
</template>

怎么想: 这种写法本身没错,但页面组件一多,导入语句会反复出现。自动注册的目标不是“全局注册所有组件”,而是在当前组件里不写导入,也能直接使用模板中的 Vant 组件。

怎么做: 安装插件:

bash
pnpm add -D unplugin-vue-components

易错点: 这是开发依赖,不要装成生产依赖;也不要误以为要在 main.ts 里手动全局注册所有 Vant 组件。

在 Vite 中接入插件与 Vant 解析器 ​

为什么需要: 只安装插件还不够,Vite 配置里要启用插件,并告诉它“遇到 van-* 标签时去解析 Vant 组件”。

怎么想: 配置分两步:先导入 Components 插件,再导入 VantResolver 解析器。插件负责自动注册,解析器负责识别 Vant。

怎么做: 在 vite.config.ts 中配置:

ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Components from 'unplugin-vue-components/vite'
import { VantResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  plugins: [
    vue(),
    Components({
      resolvers: [VantResolver({ importStyle: false })],
      dts: false
    })
  ]
})

易错点: Components 放在 plugins 数组里;VantResolver 放在 resolvers 数组里。不要把两个配置项放错层级。

优化一:关闭自动导入组件样式 ​

为什么需要: 转写稿中在浏览器里检查按钮和复选框时,发现同一个组件出现了两份相同样式,上面的样式覆盖下面。原因是项目已经在 main.ts 里导入了 Vant 全部样式,而自动注册插件注册组件时又导入了一次组件样式。

怎么想: 既然全局样式已经引入,就不需要解析器再自动导入组件样式。关闭它即可避免重复。

怎么做: 在 VantResolver 中加 importStyle: false:

ts
VantResolver({ importStyle: false })

易错点: 这个配置放在 VantResolver 里,不是放在 Components 顶层。关闭后要确认 main.ts 中确实已经引入了 Vant 样式,否则页面会缺样式。

优化二:关闭自动生成类型声明文件 ​

为什么需要: 插件运行后会在项目里生成 components.d.ts,用于给自动注册组件做类型声明。但 Vant 自身已经有类型声明,这个文件会重复。转写稿中删除它后,改代码又会自动生成。

怎么想: 这个文件不是业务代码,删除后仍会生成,所以要从插件配置上关闭。

怎么做: 在 Components 配置中加:

ts
Components({
  dts: false,
  resolvers: [VantResolver({ importStyle: false })]
})

易错点: dts: false 放在 Components 里;importStyle: false 放在 VantResolver 里。两者不要写反。

验证与调试过程 ​

配置完成后,回到 views/login/index.vue,删掉手动导入,只保留模板:

vue
<template>
  <van-button>按钮</van-button>
  <van-checkbox>复选框</van-checkbox>
</template>

刷新浏览器,按钮和复选框正常显示,说明自动注册生效。再打开元素面板检查按钮和复选框样式,发现重复样式消失,说明 importStyle: false 生效。删除 components.d.ts 后修改代码,文件不再自动生成,说明 dts: false 生效。

易错点: 如果页面报“组件未解析”,先检查插件是否安装、vite.config.ts 是否重启生效、标签名是否写对。另外,转写稿提到一个彩蛋:配置该插件后,components 目录下的组件也会自动注册,后续封装通用组件时会用到。

本节目标:封装通用顶部通栏 ​

登录页第一个要完成的区域是顶部通栏。转写稿里先明确了一个判断:几乎每个页面都有顶部通栏,而且长得差不多,所以不要在每个页面里重复写,而是封装成通用组件 cp-nav-bar。本节只完成“结构和样式”,功能(动态标题、右侧文字、点击事件、回退)留到后续小节。

为什么需要先做结构?因为顶部通栏是页面骨架的一部分,结构不对,后面的功能和页面布局都会返工。怎么想?基于 Vant 的 van-nav-bar 二次封装:结构交给 Vant,样式再按设计稿覆盖。怎么做?先建组件、在登录页使用,再补 fixed、left-arrow、title、right-text,最后用深度选择器改样式。易错点:不要把 cp-nav-bar 当成普通页面内容直接写一堆 div,也不要在本节提前实现 props/emit。

创建组件并验证自动注册 ​

为什么需要先建组件?因为顶部通栏要被多个页面复用,必须先有独立组件文件。怎么想?在 src/components 下新建 cp-nav-bar.vue,登录页直接使用 <cp-nav-bar />。怎么做?组件先初始化基本结构,然后到 src/views/login/index.vue 中写上:

vue
<template>
  <div class="login">
    <cp-nav-bar />
  </div>
</template>

保存后到浏览器看登录页,如果页面上出现组件内容,说明 components 下的组件已被自动注册。转写稿在这里专门验证过:没有手动 import,组件也能使用。易错点:自动注册依赖上一节配置;如果没配置,仍需显式导入。组件名、文件名要一致,避免大小写或路径写错。

用 van-nav-bar 搭出通栏结构 ​

为什么不用自己写 div?因为 Vant 已经提供了导航栏的结构和交互基础,二次封装更省事。怎么想?把组件里的 div 换成 van-nav-bar,再用属性控制结构。怎么做?组件模板写成:

vue
<template>
  <van-nav-bar
    fixed
    left-arrow
    title="登录"
    right-text="注册"
  />
</template>

这里的对应关系是:fixed 做固定定位,页面滚动时通栏不动;left-arrow 显示左侧返回箭头;title 设置标题;right-text 设置右侧文字。转写稿中先写死“登录”和“注册”,是为了先看结构,后面再改成动态。易错点:left-arrow 不要写成 left-alone;right-text 不要写成 rightText 属性;fixed 加上后可能遮住下面按钮,这是固定定位的正常现象,不是样式坏了。

浏览器调试:先找选择器再覆盖 ​

为什么不能直接凭感觉写样式?因为 Vant 内部元素有固定类名,必须先确认选择器。怎么想?先看现象:左侧箭头是绿色且偏小,标题偏大。怎么做?打开浏览器开发者工具,检查箭头元素,看到它对应 .van-nav-bar__arrow;标题对应 .van-nav-bar__title。转写稿的调试过程就是先定位选择器,再回 VS Code 覆盖。易错点:不要覆盖 .van-nav-bar 整个组件,否则会影响布局;箭头和标题的选择器都带双下划线 __,不要漏写。

用 :deep() 覆盖 Vant 内部样式 ​

为什么需要 :deep()?因为组件样式通常写在 scoped 中,而箭头、标题是 Vant 子组件内部元素,普通选择器作用不到。怎么想?用深度作用选择器穿透到子组件内部。怎么做?在 cp-nav-bar.vue 中写:

vue
<style scoped lang="scss">
:deep(.van-nav-bar__arrow) {
  color: var(--cp-text1);
  font-size: 18px;
}

:deep(.van-nav-bar__title) {
  font-size: 15px;
}
</style>

--cp-text1 是项目里定义的黑色变量,箭头改成黑色并放大到 18px;标题改成 15px。保存后回浏览器验证:箭头变黑变大,标题变小。易错点::deep() 不要写成 :dep();括号不要漏;CSS 变量名不要拼错;font-size 要带单位。

小结与易错点 ​

本节完成的是 cp-nav-bar 的结构和样式:建组件、自动注册验证、使用 van-nav-bar 加 fixed/left-arrow/title/right-text、通过开发者工具找选择器、用 :deep() 覆盖箭头和标题样式。最容易错的是把结构和功能混在一起写;本节先写死文字是合理的过渡。另一个易错点是固定定位后遮挡内容,后续页面布局再处理间距。完成后再提交代码,下一节再实现标题、右侧文字和点击事件等功能。

代码示例 ​

1. 登录页路由规则 + 路由出口 ​

ts
// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    // 一级路由:整页切换
    {
      path: '/login',
      component: () => import('@/views/login/index.vue')
    }
  ]
})

export default router
vue
<!-- src/App.vue -->
<script setup lang="ts"></script>

<template>
  <!-- 一级路由出口,放在 App 根组件里 -->
  <router-view />
</template>

关键行与易错点

  • path: '/login' 与笔记里的路由规则表保持一致,访问地址就是 /login。
  • component: () => import('@/views/login/index.vue') 是路由懒加载,返回一个 import 函数而不是直接 import Login from ... 后赋值。
  • 配完路由规则必须加路由出口,否则页面白屏——出口写在 App.vue 里,因为这里是一级路由(整页替换)。
  • 转写稿特别强调:App.vue 里原来的测试代码要全部删掉,只保留 <router-view />,否则会和新页面叠在一起。

2. Vite 组件自动注册配置(unplugin-vue-components) ​

ts
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Components from 'unplugin-vue-components/vite'
import { VantResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  plugins: [
    vue(),
    // 第一步:组件自动注册插件
    Components({
      // 第二步:配置 Vant UI 组件库解析器
      resolvers: [
        VantResolver({
          // 优化一:不再自动导入组件样式(main.ts 里已全量引入,避免样式重复)
          importStyle: false
        })
      ],
      // 优化二:不生成 components.d.ts(Vant 自带类型声明,避免类型声明文件重复)
      dts: false
    })
  ]
})

关键行与易错点

  • 两个解析器/选项的位置不能放错:importStyle 是 VantResolver() 的参数,dts 是 Components() 的参数。
  • importStyle: false 的原因:main.ts 里已经把 Vant 全部样式引入了,插件再自动导入一份就会出现「上面一份样式、下面一份一模一样样式」的重复。
  • dts: false 的原因:插件默认自动生成 components.d.ts 做类型声明,但 Vant 本身已有类型声明,属于重复文件。
  • 配置完成后,组件里不要再写 import { Button } from 'vant',直接写 <van-button> 即可;components/ 目录下的自定义组件也会被自动注册(后面封装通用组件时会用到这个彩蛋)。

3. cp-nav-bar 组件:结构样式 + 功能 + 类型声明 ​

vue
<!-- src/components/cp-nav-bar.vue -->
<script setup lang="ts">
import { useRouter } from 'vue-router'

// 1. props:标题、右侧文字,都是可选的
defineProps<{
  title?: string
  rightText?: string
}>()

// 2. 自定义事件:点击右侧文字
const emit = defineEmits<{
  (e: 'click-right'): void
}>()

const router = useRouter()

// 3. 回退功能:有历史记录就 back,没有就回首页
const onClickLeft = () => {
  if (history.state?.back) {
    router.back()
  } else {
    router.push('/')
  }
}

// 4. 右侧文字点击 → 抛出事件给使用方
const onClickRight = () => {
  emit('click-right')
}
</script>

<template>
  <van-nav-bar
    fixed
    left-arrow
    :title="title"
    :right-text="rightText"
    @click-left="onClickLeft"
    @click-right="onClickRight"
  />
</template>

<style scoped lang="less">
/* 深度作用选择器,覆盖 Vant 内部元素样式 */
:deep() {
  .van-nav-bar__arrow {
    color: var(--cp-text1); /* 箭头变黑 */
    font-size: 18px; /* 箭头变大 */
  }
  .van-nav-bar__title {
    font-size: 15px; /* 标题小一号 */
  }
}
</style>
ts
// src/types/components.d.ts —— 给自动注册的全局组件补类型
import CpNavBar from '@/components/cp-nav-bar.vue'

declare module 'vue' {
  interface GlobalComponents {
    // 从组件对象中取出类型,赋给全局组件名
    CpNavBar: typeof CpNavBar
  }
}

export {}
vue
<!-- src/views/login/index.vue 中的使用方式 -->
<template>
  <cp-nav-bar title="登录" right-text="注册" @click-right="fn" />
</template>

关键行与易错点

  • fixed、left-arrow、:title、:right-text 都是 van-nav-bar 的官方属性,结构不用自己写 div 拼。
  • defineProps 用泛型写法时属性名是驼峰 rightText,模板里绑定时写成 :right-text;传参时写 right-text="注册"。
  • 右侧文字没传值的时候 click-right 不会触发(Vant 内部行为),所以不用额外判断空值。
  • 回退判断用 history.state?.back:转写稿中提到 history.state 的类型是 any,加可选链 ?. 防止直接报错。
  • 覆盖 Vant 内部样式必须用 :deep(),否则 scoped 样式打不到组件内部的 .van-nav-bar__arrow / .van-nav-bar__title。
  • 类型声明文件里:declare module 'vue' 和 interface GlobalComponents 都是固定写法,不能改名;typeof CpNavBar 是从组件这个 JS 变量里取类型(TS 的 typeof 用法)。不写这份声明,鼠标悬停组件会显示 any,right-text 传数字也不会报错。

常见错误 ​

  1. 配了 /login 但页面空白
    现象:地址能访问,页面无内容。
    原因:App.vue 没保留一级路由出口,或旧测试代码/容器遮挡。
    修法:在 App.vue 只保留 <router-view />,删除旧测试结构与内容。

  2. 自动注册后 Vant 组件仍报未注册,或样式出现两份
    现象:按钮/复选框不识别,或浏览器里同一组件样式重复。
    原因:只加了 Components 插件,没配 VantResolver;或未关闭自动样式导入、未关闭 dts 生成。
    修法:在 Vite 配置中同时配置 Components({ resolvers: [VantResolver({ importStyle: false })], dts: false }),并确认 main.ts 已统一引入 Vant 样式。

  3. 点击右侧文字没有触发自定义事件
    现象:父组件绑定了事件但点击无反应,或右侧文字为空时也期望触发。
    原因:事件名拼写不一致;未 defineEmits 后 emit;右侧文字为空时 Vant 本身不会触发 click-right。
    修法:子组件监听 click-right 后 emit('click-right'),父组件统一事件名;需要空文字可点击时不要依赖 Vant 的 click-right。

  4. 返回按钮行为不符合预期
    现象:直接访问 /login 点返回没回首页,或从其他页进入后没有正常回退。
    原因:只调用 router.back(),未判断 history.state.back。
    修法:有 history.state.back 时 router.back(),否则 router.push('/');访问 state 时加可选链避免报错。

  5. CpNavBar 样式覆盖不生效
    现象:箭头颜色、字号、标题字号改不动。
    原因:scoped 样式无法直接作用 Vant 内部元素,或选择器类名写错。
    修法:使用 :deep(.van-nav-bar__arrow)、:deep(.van-nav-bar__title) 等实际类名覆盖,先在浏览器确认选择器。

  6. 自动注册组件没有类型提示
    现象:CpNavBar 属性无提示,传错类型也不报错。
    原因:自动注册组件没有全局组件类型声明。
    修法:在 components.d.ts 中扩展 vue 的 GlobalComponents,用 typeof CpNavBar 赋给组件名,并确保组件名、导入路径一致。

  7. 登录页出现多余 #app 嵌套或控制台多余日志
    现象:DOM 多一层容器,控制台持续打印。
    原因:沿用 Vue2 挂载认知保留了外层 div.app;路由入口测试日志未清理。
    修法:删除 App.vue 外层多余容器,保留路由出口;清理 router/index.ts 中的测试打印和测试链接。

练习 ​

  1. 配置 /login 路由并使用路由懒加载;分别验证“直接访问 /login”和“从 /home 跳转到 /login”两种场景。
  2. 配置 unplugin-vue-components + VantResolver,在登录页使用 van-button、van-checkbox,检查组件可用、样式只有一份、不再生成多余类型声明文件。
  3. 为 CpNavBar 增加 title、right-text 两个可选 props,并实现 click-right 自定义事件;父组件验证:有右侧文字时点击触发,无右侧文字时不触发。
  4. 实现 CpNavBar 返回逻辑:有历史记录时回退,无历史记录时跳首页;用直接访问和带跳转访问两种方式各测一次。
  5. 为 CpNavBar 添加全局组件类型声明,验证 right-text 有提示,且传入 number 时出现类型错误。

课堂画面 ​

课堂画面 01

课堂画面 02

课堂画面 03

课堂画面 04

课堂画面 05

课堂画面 06

原视频对照 ​

#视频时长
1路由规则和准备登录页面06:26
2组件自动注册配置13:40
3cp-nav-bar组件-结构和样式09:52
4cp-nav-bar功能标题和右侧文字与右侧文字自定义事件08:58
5cp-nav-bar功能-回退08:32
6cp-nav-bar组件类型08:37
7登录页面布局和清理代码08:19

小结 ​

  • 先定路由层级再写页面:一级路由管整页切换,二级路由管布局容器内局部切换。
  • 自动注册不是“装插件就完事”,resolver、dts、importStyle 三个配置点要一起检查。
  • 通用导航组件按“结构样式 → props/emit 功能 → 类型声明”推进,边界更清晰。
  • 覆盖 Vant 内部样式必须用 :deep,选择器以浏览器实际类名为准。
  • 回退逻辑要区分有无历史记录,不能无脑 router.back()。
  • 自动注册组件必须补全局类型声明,否则提示和类型校验会退化。
  • Vue3 根组件是插入 #app,不要保留多余外层容器;测试代码和日志要及时清理。
  • 每个功能点都用浏览器验证:路由可达、样式单份、事件触发、类型报错、直接访问行为。