主题
面经 PC 端(上)(二)
本页对应 面经 PC 端(上),共 7 段视频,约 1 小时 2 分。
学习目标
- 能使用
mapState/mapGetters放入computed、mapMutations/mapActions放入methods,在组件中简化 Vuex 数据访问与方法调用。 - 能按命名空间拆分 Vuex 模块,编写
namespaced: true的模块文件,并在index.js中导入、注册为模块。 - 能在组件中分别用直接方式和辅助方法访问分模块后的
state/getters,并使用commit/dispatch携带“模块名/方法名”更新或请求数据。 - 能使用
json-server基于 JSON 文件提供简易 REST 接口,并验证列表查询、单条查询、新增、修改、删除接口。 - 能设计购物车 Vuex 模块,定义
list状态、更新list的 mutation、异步获取数据的 action,并用 axios 获取数据后提交 mutation 写入仓库。 - 能完成路由主题色配置、二级路由配置,以及登录页静态布局和登录表单细节实现,并通过页面效果与交互进行检查。
知识点
先明确目标:把 Vant 默认蓝色改成品牌橙色
为什么需要:整体网站风格是橙色,而 Vant 组件默认主题色偏蓝。如果逐个组件写样式覆盖,不仅分散、难维护,还容易漏改。更合适的做法是统一覆盖 Vant 的主题变量,让按钮、链接等使用主色的组件一起变化。
怎么想:Vant v2 的主题定制依赖 Less 变量覆盖。要让它生效,需要同时做两件事:第一,按需引入时不要只加载编译后的 CSS,而要加载 Less 源样式;第二,在 Less 编译阶段用 modifyVars 覆盖变量。笔记中给出的官方主题说明是:
https://vant-contrib.gitee.io/vant/v2/#/zh-CN/theme
怎么做:先改 babel.config.js,再改 vue.config.js,最后重启开发服务器。
易错点:只改 vue.config.js 而不改 Babel 样式路径,变量覆盖可能不生效;改完不重启,构建配置不会按新配置重新生效;变量名要按 Vant v2 文档使用,不要自己臆造。
配置 Babel:让按需引入加载 Less 源样式
为什么需要:按需引入通常加载的是组件对应样式文件。若仍加载编译后的 CSS,modifyVars 就没有机会参与 Less 编译,主题变量覆盖自然无效。
怎么想:babel-plugin-import 的 style 选项可以指定样式路径。把默认样式路径改成 ${name}/style/less,就是让 Vant 组件引入 Less 源文件。
怎么做:在 babel.config.js 中保留原有 preset,并在 plugins 中配置 import:
jsx
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins: [
['import', {
libraryName: 'vant',
libraryDirectory: 'es',
// 指定样式路径
style: (name) => `${name}/style/less`
}, 'vant']
]
}易错点:style 要写成函数并返回模板字符串;libraryDirectory 不要漏;插件数组第三项 'vant' 是唯一标识,不要随意改;改完 Babel 配置后要重启服务器,必要时清理构建缓存再试。
配置 vue.config.js:用 modifyVars 覆盖主题变量
为什么需要:Vant 的主题色由 Less 变量控制。业务希望全站统一成橙色,就应该在构建配置里覆盖变量,而不是在页面里零散写 !important。
怎么想:Vue CLI 项目可以通过 css.loaderOptions.less.lessOptions.modifyVars 把变量注入 Less 编译过程。笔记中直接把 blue 覆盖为 #FA6D1D。
怎么做:在 vue.config.js 中写入:
jsx
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
css: {
loaderOptions: {
less: {
lessOptions: {
modifyVars: {
// 直接覆盖变量
'blue': '#FA6D1D',
},
},
},
},
},
})易错点:lessOptions 层级不要写错;颜色值要合法;变量名要与 Vant v2 主题变量一致;如果项目里还有自定义 Less 变量,注意不要互相覆盖;不同 Vue CLI 版本对配置写法可能有差异,以当前项目实际编译结果为准。
重启服务器并验证效果
为什么需要:babel.config.js 和 vue.config.js 都属于构建期配置,开发服务器启动时读取。改完后不重启,页面可能仍使用旧配置。
怎么想:先重启,再看编译是否报错,最后在页面上观察使用主色的 Vant 组件是否变成橙色。调试时可重点检查两点:按需引入是否加载了 Less 样式;modifyVars 是否进入 Less 编译。
怎么做:停止当前终端服务,重新执行启动命令;打开页面查看按钮、链接等主色组件;如果颜色没变,先看终端是否有 Less 编译错误,再检查两个配置文件是否都保存、路径是否写对。
易错点:只重启浏览器不重启开发服务器;只改一个配置文件;终端报错被忽略;浏览器缓存造成误判。笔记最后强调“重启服务器生效”,这是必须执行的一步。
关于转写稿的说明
本节转写稿主要讲 Vuex 的 mutations、actions、辅助方法、分模块以及购物车数据请求,与“配置 Vant 主题色”不是同一知识点。为避免编造,本文没有把 Vuex 的推导过程硬套到主题色配置中;主题色部分严格按本节笔记和其中给出的 Vant 主题链接扩写。实际调试时,仍应以终端编译结果和页面组件颜色为准。
二级路由要解决什么问题
为什么需要:登录、注册、文章详情这类页面通常是“整页切换”;而面经、收藏、喜欢、我的这类页面,底部有同一个 tabbar,只有中间内容在变。如果每个页面都单独写一遍 tabbar,既重复又难维护。
怎么想:把“带 tabbar 的外壳”抽成 Layout,把四个内容页作为它的子路由,让 Layout 内部只切换 router-view。
怎么做:根路由 / 指向 Layout,并配置 children;Layout 中放二级路由出口和 tabbar。
易错点:不要把二级页面继续写成根级路由,否则它们不会在 Layout 的 router-view 中渲染。

先看整体路由结构
为什么需要:二级路由不是单独一条配置,而是“父路由 + 子路由 + 出口”三者配合。先看清结构,后面才不会把路径写散。
怎么想:/login、/register、/article/:id 是独立页面;/ 是带 Layout 的父路由,article、like、collect、user 是它的子路由。
怎么做:在 router/index.js 中导入组件,按下面的结构配置。
易错点:父路由的 component 必须是 Layout,不是某一个内容页;子路由要放在 children 数组里。
jsx
import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '@/views/Login'
import Register from '@/views/Register'
import Detail from '@/views/Detail'
import Layout from '@/views/Layout'
import Like from '@/views/Like'
import Article from '@/views/Article'
import Collect from '@/views/Collect'
import User from '@/views/User'
Vue.use(VueRouter)
const router = new VueRouter({
routes: [
{ path: '/login', component: Login },
{ path: '/register', component: Register },
{ path: '/article/:id', component: Detail },
{
path: '/',
component: Layout,
redirect: '/article',
children: [
{ path: 'article', component: Article },
{ path: 'like', component: Like },
{ path: 'collect', component: Collect },
{ path: 'user', component: User }
]
}
]
})
export default router配置父路由与重定向
为什么需要:用户访问 / 时,不能只显示一个空壳 Layout,需要默认进入一个二级页面。
怎么想:/ 作为父路由承载 Layout,再用 redirect: '/article' 把默认访问导向面经页。
怎么做:保留 path: '/'、component: Layout、redirect: '/article',并在 children 中写四个子路由。
易错点:redirect 写错会导致访问首页空白;子路由的 path 建议写 article,不要写成 /article。子路由以 / 开头会被当作根路径,父子嵌套关系和激活状态容易出问题。
在 Layout 中放路由出口
为什么需要:父路由匹配到 Layout 后,具体子页面要显示在哪里,必须由 router-view 决定。
怎么想:Layout 是外壳,中间区域放二级 router-view,底部放 tabbar。
怎么做:在 layout.vue 的模板中先写 <router-view></router-view>,再写 van-tabbar。
易错点:忘记写 router-view 时,地址变了但内容不显示;router-view 放错位置会导致 tabbar 被一起替换掉。
jsx
<template>
<div class="layout-page">
//路由出口
<router-view></router-view>
<van-tabbar route>
<van-tabbar-item to="/article" icon="notes-o">面经</van-tabbar-item>
<van-tabbar-item to="/collect" icon="star-o">收藏</van-tabbar-item>
<van-tabbar-item to="/like" icon="like-o">喜欢</van-tabbar-item>
<van-tabbar-item to="/user" icon="user-o">我的</van-tabbar-item>
</van-tabbar>
</div>
</template>配置 tabbar 的路由模式
为什么需要:底部导航要能点击切换二级路由,并且当前项要有选中状态。
怎么想:Vant 的 van-tabbar 支持 route 模式,开启后 van-tabbar-item 的 to 就按路由地址跳转。
怎么做:给 van-tabbar 加 route,四个 van-tabbar-item 的 to 分别写 /article、/collect、/like、/user。
易错点:不写 route 时,to 不一定按路由模式工作;to 地址要和子路由最终路径一致;图标名和文字按笔记保留,不要随意改动。
联调时的检查顺序
为什么需要:二级路由出错时,问题可能在路由表、出口或 tabbar 三处,按顺序排查最快。
怎么想:先看地址是否能匹配父路由,再看 Layout 是否渲染,最后看子页面是否进入 router-view。
怎么做:访问 / 应重定向到 /article;点击 tabbar 应切换到 /collect、/like、/user;访问 /article/:id 应进入详情页。
易错点:Detail 按笔记放在根级路由,不要误放进 children;子路由路径、to 地址、redirect 地址三者要统一;组件导入路径和文件名要对应,避免因导入失败导致路由不渲染。
先看目标:先把登录页静态骨架搭出来

本节目标是完成“面经登录”的静态布局:顶部导航栏、中间表单、底部“注册账号”入口。为什么先做静态布局?因为登录页的交互依赖表单结构和校验规则,如果结构没搭好,后面接接口时容易边改样式边改逻辑。怎么想?把页面拆成三块:van-nav-bar 负责标题,van-form 负责表单容器,van-field 负责用户名和密码输入,van-button 负责提交;注册入口先用 router-link 跳转。怎么做?先在 vant-ui.js 注册组件,再在 Login.vue 中写模板和数据。易错点:不要一上来就写 axios;先把页面渲染和表单提交事件跑通。
转写稿中关于 Vuex 分模块、购物车接口的内容属于后续章节,本节不展开;但其中反复强调的调试顺序可以借用:先导入/注册,再在组件中使用,最后刷新页面验证结果。
注册 Vant 组件:按需引入后要确保组件可用
为什么需要注册?Vant 组件不是浏览器原生标签,未注册时模板里的 van-nav-bar、van-form 等无法按预期渲染。怎么想?项目里通常统一在 vant-ui.js 做按需注册,页面只负责使用。怎么做?按笔记先引入并 Vue.use:
jsx
import Vue from 'vue'
import {
NavBar,
Form,
Field
} from 'vant'
Vue.use(NavBar)
Vue.use(Form)
Vue.use(Field)易错点:笔记这段注册代码里没有出现 Button,但 Login.vue 使用了 van-button。实际项目中要确认 Button 也已注册,或者项目已全局引入 Vant;否则按钮可能不渲染或报组件未注册。另一个易错点是组件名和标签名对应关系,不要漏写 Vue.use。
van-form 与 van-field:表单结构和校验规则
为什么需要表单组件?因为登录页不仅要输入,还要做“必填”和“长度/格式”校验。怎么想?van-form 包住所有字段,van-field 通过 v-model 绑定数据,通过 name 参与提交值,通过 rules 声明校验。怎么做?在 Login.vue 中写:
jsx
<template>
<div class="login-page">
<!-- 导航栏部分 -->
<van-nav-bar title="面经登录" />
<!-- 一旦form表单提交了,就会触发submit,可以在submit事件中
根据拿到的表单提交信息,发送axios请求
-->
<van-form @submit="onSubmit">
<!-- 输入框组件 -->
<!-- \w 字母数字_ \d 数字0-9 -->
<van-field
v-model="username"
name="username"
label="用户名"
placeholder="用户名"
:rules="[
{ required: true, message: '请填写用户名' },
{ pattern: /^\w{5,}$/, message: '用户名至少包含5个字符' }
]"
/>
<van-field
v-model="password"
type="password"
name="password"
label="密码"
placeholder="密码"
:rules="[
{ required: true, message: '请填写密码' },
{ pattern: /^\w{6,}$/, message: '密码至少包含6个字符' }
]"
/>
<div style="margin: 16px">
<van-button block type="info" native-type="submit">提交</van-button>
</div>
</van-form>
</div>
</template>
<script>
export default {
name: 'LoginPage',
data () {
return {
username: 'zhousg',
password: '123456'
}
},
methods: {
onSubmit (values) {
console.log('submit', values)
}
}
}
</script>易错点:v-model 必须绑定到 data 中声明的字段;name 决定提交时 values 里的键名;pattern: /^\w{5,}$/ 中 \w 表示字母、数字、下划线,不包含中文;密码用了 type="password" 才能隐藏输入。按钮必须写 native-type="submit",否则不会触发表单的 @submit。
提交事件:先打印 values,再接接口
为什么先写 onSubmit?因为要确认表单校验通过后能拿到哪些数据。怎么想?Vant 表单提交时会触发 @submit,参数就是表单值;本节先 console.log,后续再把打印替换成 axios 请求。怎么做?保持上面的 onSubmit(values),在浏览器中填写用户名密码并提交,打开控制台看输出。易错点:不要把 @submit 写成 @click;不要忘记 native-type="submit";如果校验不通过,onSubmit 不会执行,这是正常现象。
注册入口与样式:用 router-link 跳转
为什么需要注册入口?登录页要能引导新用户去注册。怎么想?用 router-link 比手写 a 标签更符合 Vue Router 的跳转方式。怎么做?在表单后加:
vue
<template>
<div class="login-page">
<van-nav-bar title="面经登录" />
<van-form @submit="onSubmit">
...
</van-form>
<router-link class="link" to="/register">注册账号</router-link>
</div>
</template>再补样式:
jsx
<style lang="less" scoped>
.link {
color: #069;
font-size: 12px;
padding-right: 20px;
float: right;
}
</style>易错点:to="/register" 要跟路由配置一致;float: right 需要父容器能容纳浮动元素,必要时给外层加清除浮动或改用布局;scoped 下样式只作用于当前组件,不要指望它影响子组件内部结构。调试时按“刷新看导航栏→输入看校验→提交看控制台→点注册看路由”的顺序排查即可。
说明
本节转写稿主要围绕 Vuex 分模块、购物车数据与 json-server 展开,和“登录表单中的细节分析”这六条笔记没有直接对应关系;为避免编造,下面只依据笔记条目扩写,不把无关的 Vuex 推导硬套进来。本节笔记未附图片和代码,因此不额外补造图片或代码。
1. @submit 事件:统一表单提交入口
为什么需要:登录表单既要支持点击“登录”按钮提交,也要支持在输入框内按回车提交。把提交逻辑统一挂到表单的 submit 事件上,比只监听按钮点击更稳妥。
怎么想:提交动作属于“表单整体行为”,不是某一个按钮的私有行为。因此应把处理函数绑定在 <form> 上,让按钮触发原生提交,再由 @submit 接管。
怎么做:在表单标签上写 @submit,提交按钮使用提交类型;处理函数中先判断是否需要阻止默认刷新,再收集表单数据并发请求。
易错点:按钮类型写错导致不触发或意外触发;忘记处理默认提交造成页面刷新;把 @submit 写到按钮上,结果回车提交时逻辑不执行。
2. v-model 双向绑定:让输入值与数据同步
为什么需要:登录表单需要实时拿到账号、密码等输入值。若手动监听每个输入事件再赋值,代码重复且容易漏字段。
怎么想:v-model 的本质是把“输入框显示值”和“数据字段”建立双向关系:输入改变数据,数据改变也会回显到输入框。
怎么做:为每个输入项准备独立的数据字段,在输入框上使用 v-model 绑定对应字段;提交时直接读取这些字段组织参数。
易错点:多个输入框绑定同一个字段;绑定到没有 setter 的计算属性;初始值类型不统一,导致校验或接口参数异常;误以为 v-model 会自动完成接口字段映射。
3. name 属性:收集参数的 key 要与接口文档对应
为什么需要:表单收集出来的数据最终要按接口要求的字段名提交。name 往往承担“这个输入项叫什么参数”的职责,若与接口文档不一致,后端就收不到或收错字段。
怎么想:先看接口文档的请求参数字段,再决定表单控件的 name;不要凭习惯起名,也不要在提交时临时猜字段。
怎么做:逐个输入框设置 name,并和接口文档逐字核对;若使用表单组件封装收集逻辑,也要确认最终提交对象的 key 与文档一致。
易错点:前端写 username、后端要 userName;大小写、下划线、驼峰不一致;嵌套字段未按文档组织;复制粘贴后漏改 name。
4. label:输入框的标题与可访问性
为什么需要:用户需要知道每个输入框填什么;label 既提供可见标题,也能提升可访问性,让点击标题时聚焦对应输入框。
怎么想:label 不是装饰文字,而是和输入控件建立关联的说明。标题要清楚、简短,并与校验提示区分开。
怎么做:为输入框设置唯一 id,让 label 的 for 指向该 id;也可用 label 包裹输入框建立关联。
易错点:只写视觉文字却不关联输入框;for 与 id 不匹配;用 placeholder 代替 label,输入后标题消失,用户难以确认字段含义。
5. :rules:集中管理表单校验规则
为什么需要:登录表单不能只靠后端校验。前端需要及时提示必填、格式等问题,减少无效请求,也提升填写体验。
怎么想:校验规则应和字段一一对应,明确“哪个字段、什么规则、何时触发”。规则配置要和数据字段名保持一致,否则规则不会作用到目标输入项。
怎么做:在支持 :rules 的表单或表单项上配置规则对象;字段名与绑定数据、name/prop 对应;按需设置必填、长度、格式及触发时机。
易错点:规则字段名与数据字段不一致;只配规则但未触发表单校验;自定义校验回调未正确返回;提示文案与 placeholder 冲突。
6. placeholder:提示语不是字段标题
为什么需要:placeholder 用于给用户一个简短示例或格式提示,例如“请输入手机号”“请输入密码”,帮助用户理解输入要求。
怎么想:它应辅助 label,而不是替代 label。提示要短、准确,不能与校验规则矛盾。
怎么做:为输入框设置简洁的 placeholder,说明格式或示例;真正的字段名称仍由 label 承担。
易错点:把 placeholder 当标题,输入后信息消失;提示内容过长被截断;提示“请输入6位密码”但规则要求8位;用提示语掩盖校验缺失。
课件图示








代码示例
示例 1:Vant 主题色覆盖(babel.config.js + vue.config.js)
jsx
// babel.config.js —— 让 Vant 的样式指向 less 源文件
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins: [
['import', {
libraryName: 'vant',
libraryDirectory: 'es',
// 指定样式路径(关键:必须是 less 源码,否则无法覆盖变量)
style: (name) => `${name}/style/less`
}, 'vant']
]
}jsx
// vue.config.js —— 用 less 的 modifyVars 覆盖 Vant 变量
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
css: {
loaderOptions: {
less: {
lessOptions: {
modifyVars: {
// 直接覆盖变量
'blue': '#FA6D1D',
},
},
},
},
},
})关键行与易错点
style: (name) =>${name}/style/less`` 是整套主题色生效的前提:只有让 Vant 引入 less 源码,modifyVars才有变量可覆盖;写成默认的 css 路径则改了也不变色。modifyVars里写的是 Vant 内部定义的 less 变量名(如blue),不带@前缀,值才是颜色。- 两个文件改完 必须重启 dev server 才生效,热更新不会重新编译 babel 与 less 变量。
vue.config.js里less层级是loaderOptions.less.lessOptions.modifyVars,少写一层lessOptions是常见报错点。
示例 2:二级路由配置 + Layout 中的路由出口与 Tabbar
jsx
// router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '@/views/Login'
import Register from '@/views/Register'
import Detail from '@/views/Detail'
import Layout from '@/views/Layout'
import Like from '@/views/Like'
import Article from '@/views/Article'
import Collect from '@/views/Collect'
import User from '@/views/User'
Vue.use(VueRouter)
const router = new VueRouter({
routes: [
{ path: '/login', component: Login },
{ path: '/register', component: Register },
{ path: '/article/:id', component: Detail },
{
path: '/',
component: Layout,
redirect: '/article',
children: [
{ path: 'article', component: Article },
{ path: 'like', component: Like },
{ path: 'collect', component: Collect },
{ path: 'user', component: User }
]
}
]
})
export default routervue
<!-- layout.vue -->
<template>
<div class="layout-page">
<!-- 路由出口:二级路由的组件会渲染在这里 -->
<router-view></router-view>
<!-- route 模式:选中项由当前路由自动决定 -->
<van-tabbar route>
<van-tabbar-item to="/article" icon="notes-o">面经</van-tabbar-item>
<van-tabbar-item to="/collect" icon="star-o">收藏</van-tabbar-item>
<van-tabbar-item to="/like" icon="like-o">喜欢</van-tabbar-item>
<van-tabbar-item to="/user" icon="user-o">我的</van-tabbar-item>
</van-tabbar>
</div>
</template>关键行与易错点
- 子路由的
path写'article'(不带前导斜杠),最终会拼接成/article;写成'/article'虽然能跳,但会被当成根路径,失去父子嵌套关系。 - 父路由
/配了redirect: '/article',保证一进首页就有默认子页面,否则<router-view>会是空白。 <router-view>必须放在Layout组件里,且要在 tabbar 之前/之外,否则子页面会被 Tabbar 遮住或渲染错位置。<van-tabbar route>的route属性开启后,to会走路由跳转并自动高亮,不能再用v-model手动控制激活项,两者别混用。
示例 3:登录页静态布局 + 表单校验
jsx
// vant-ui.js —— 按需注册用到的组件
import Vue from 'vue'
import {
NavBar,
Form,
Field
} from 'vant'
Vue.use(NavBar)
Vue.use(Form)
Vue.use(Field)vue
<!-- Login.vue -->
<template>
<div class="login-page">
<!-- 导航栏部分 -->
<van-nav-bar title="面经登录" />
<!-- 一旦form表单提交了,就会触发submit,可以在submit事件中
根据拿到的表单提交信息,发送axios请求
-->
<van-form @submit="onSubmit">
<!-- 输入框组件 -->
<!-- \w 字母数字_ \d 数字0-9 -->
<van-field
v-model="username"
name="username"
label="用户名"
placeholder="用户名"
:rules="[
{ required: true, message: '请填写用户名' },
{ pattern: /^\w{5,}$/, message: '用户名至少包含5个字符' }
]"
/>
<van-field
v-model="password"
type="password"
name="password"
label="密码"
placeholder="密码"
:rules="[
{ required: true, message: '请填写密码' },
{ pattern: /^\w{6,}$/, message: '密码至少包含6个字符' }
]"
/>
<div style="margin: 16px">
<van-button block type="info" native-type="submit">提交</van-button>
</div>
</van-form>
<router-link class="link" to="/register">注册账号</router-link>
</div>
</template>
<script>
export default {
name: 'LoginPage',
data () {
return {
username: 'zhousg',
password: '123456'
}
},
methods: {
onSubmit (values) {
console.log('submit', values)
}
}
}
</script>
<style lang="less" scoped>
.link {
color: #069;
font-size: 12px;
padding-right: 20px;
float: right;
}
</style>关键行与易错点
@submit由van-form内部的提交按钮触发,前提是按钮必须写native-type="submit";漏写则点击按钮只触发 click,不会触发 submit,校验也不执行。name属性决定onSubmit(values)里收集到的 key 名,要和接口字段对应;只写v-model不写name,values 里就拿不到这个字段。v-model负责双向绑定,:rules负责校验,两者缺一不可;rules前要加冒号(绑定数组/对象),写成rules="[...]"会变成字符串而失效。pattern里/^\w{5,}$/的\w是字母数字下划线,注意转义符不能丢。- 新用到的 Vant 组件(NavBar / Form / Field)必须在
vant-ui.js里Vue.use注册,否则模板里标签不渲染、也不报明显错误。
常见错误
现象:改了主题色,页面仍是默认蓝色。
原因:只改了modifyVars,但 Vant 样式入口仍走默认 css,或改完配置未重启。
修法:确认babel.config.js中style: (name) =>${name}/style/less``,再检查vue.config.js的modifyVars,最后重启开发服务器。现象:访问
/能进 Layout,但二级页面空白或 tabbar 不选中。
原因:children的path多写了/,或van-tabbar未加route,或to与子路由不一致。
修法:子路由写成article/collect/like/user这类相对路径;父级用redirect指向默认页;tabbar 使用route且to与子路由完全对应;Layout 内保留router-view。现象:登录页点“提交”没有触发
onSubmit,或拿不到表单值。
原因:按钮未设置native-type="submit",或van-form未绑定@submit,或字段缺少v-model/name。
修法:按钮加native-type="submit";表单用@submit="onSubmit";每个van-field配好v-model和与接口一致的name。现象:用户名输入中文被判不合法,提示“至少包含5个字符”。
原因:规则用了/^\w{5,}$/,\w只匹配字母、数字、下划线。
修法:按业务改正则,例如允许中文时使用更宽松规则,或用自定义validator明确校验逻辑。现象:Vuex 分模块后,页面取值为
undefined,或dispatch/commit报 unknown action/mutation。
原因:模块未开启namespaced: true,或调用时漏了模块名。
修法:模块内必须namespaced: true;state 用$store.state.模块名.xxx;getters 用$store.getters['模块名/xxx'];commit/dispatch 用'模块名/方法名'。现象:用了
mapState/mapGetters/mapMutations/mapActions后报错或映射不到。
原因:属性类辅助方法放错到methods,方法类放错到computed;分模块后未写模块名;重名未用对象改名。
修法:mapState/mapGetters放computed,mapMutations/mapActions放methods;分模块写'模块名/成员';重名用{ 新名: '模块名/原名' }。现象:action 中请求成功,但 Vuex DevTools 里 state 没变或页面不更新。
原因:在 action 中直接改state,或请求后未提交 mutation。
修法:action 只做异步流程,拿到数据后commit('模块名/更新方法', 新数据),由 mutation 修改 state。现象:
json-server启动后访问接口 404。
原因:终端不在db.json所在目录启动,或数据最外层不是对象,或 URL 集合名与文件内字段名不一致。
修法:先cd到数据文件目录,再执行json-server --watch db.json;保证最外层是对象,如{ "list": [...] },访问/list。
练习
将项目主题色改为橙色,并验证登录按钮、tabbar 选中态、导航栏相关颜色是否生效;记录你改动的两个配置文件及重启后的验证结果。
配置
Layout下的四个二级路由:面经、收藏、喜欢、我的;要求访问/自动跳到/article,刷新/collect时 tabbar 仍选中“收藏”,页面内容正确显示。完成登录静态页:用户名至少 5 个字符、密码至少 6 个字符;点击提交能在控制台打印
values;补充“注册账号”链接跳转到/register。说明按钮为什么必须设置native-type="submit"。将 Vuex 拆成
user、todo、cart三个模块并开启命名空间;分别用“直接调用”和“辅助方法映射”各实现一次读取数据、更新数据,并验证 DevTools 中的模块结构。用
json-server提供购物车数据,在 action 中请求全部数据,再通过 mutation 写入cart模块的list;在 Vuex DevTools 中确认state.cart.list有数据,并完成数量合计展示。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 借助辅助方法使用mutation和action | 06:41 |
| 2 | 分模块后的语法 | 14:11 |
| 3 | 分模块后语法总结 | 11:52 |
| 4 | 购物车-安装 | 04:05 |
| 5 | 购物车-使用json-server提供简易接口 | 09:01 |
| 6 | 购物车-设计vuex存储库 | 07:43 |
| 7 | 购物车-发送请求获取数据 | 09:04 |
小结
主题色覆盖属于构建配置问题,
less入口、modifyVars、重启三者缺一不可。二级路由要围绕“父级 Layout + 子级相对路径 + 默认 redirect + tabbar route”形成闭环,任何一处不一致都会表现为空白或不选中。
登录表单能否提交,核心看
van-form @submit、按钮native-type="submit"、字段v-model/name/rules是否同时到位。Vuex 分模块后,
namespaced: true是访问前缀的前提;state、getters、commit、dispatch 的写法各不相同,不能混用。辅助方法的核心是“放对位置、带对模块名、重名用对象改名”,否则映射失败比直接调用更难排查。
修改 state 的唯一入口仍是 mutation;action 负责异步请求,拿到结果后 commit,才能保证 DevTools 可追踪、页面可响应。
json-server适合快速 mock 接口,启动目录、数据最外层结构、集合名与 URL 的对应关系是排错重点。配置类和模块化问题优先按“配置文件是否生效 → 是否重启 → 模块名/路径是否一致 → DevTools 是否可见”的顺序排查。