主题
面经 PC 端(上)(三)
本页对应 面经 PC 端(上),共 6 段视频,约 57 分钟。
学习目标
- 能够从 Vuex 模块的 state 中读取购物车列表,并通过
v-for渲染商品,或通过 props 将单个商品数据传给子组件完成展示。 - 能够为商品加减按钮绑定点击事件,根据当前数量计算新数量,并实现数量为 1 时禁止继续减少的边界判断。
- 能够在 Vuex action 中同时完成两件事:调用 mutation 更新仓库中的商品数量,并发送 PATCH 请求按商品 ID 更新服务器数据,刷新后数量仍保持正确。
- 能够使用 getters 计算购物车商品总数量和总价格,并在组件中通过
mapGetters映射后渲染到页面。 - 能够说明 Vuex 中 state、getters、mutation、action 的调用方式,并正确使用模块名/方法名及辅助函数写法。
- 能够使用 Vue CLI 创建 Vue2 + Vuex + SCSS + Element UI 项目,完成依赖安装、Element UI 引入配置,并使用 pnpm 启动项目验证页面效果。
知识点
本节范围与转写稿说明
本节笔记标题是“登录表单中的细节分析”,核心是 6 个表单细节:@submit、v-model、name、label、:rules、placeholder。需要说明:你给的转写稿实际在讲购物车渲染、Vuex 的 mutation/action、项目安装等内容,并没有登录表单的推导过程。因此下面不把购物车代码硬套成登录代码,只借用转写稿里可迁移的调试意识:先看页面控制台,不要只盯终端;代码改好保存后错误会自动消失,不要反复重启终端。转写稿中的“VVX/VUEX”应纠正为 Vuex,“付传子”应理解为父子传值,“mation”应理解为 mutation。本节笔记未附图片与原始代码,下面用最小表单片段标注各知识点位置。
一、@submit 事件:提交入口要可控
为什么需要:登录表单不能只靠按钮点击,用户按回车也应提交;同时要阻止浏览器默认刷新。转写稿里反复强调“一刷新数据就恢复”,登录表单同理,默认提交刷新会打断前端校验和接口流程。
怎么想:把提交统一收口到 @submit,按钮写 type="submit",在事件里做校验和请求。
怎么做:用 @submit.prevent="handleSubmit",阻止默认行为后再执行登录逻辑。
易错点:只给按钮写 @click,回车不触发;忘记 .prevent,页面刷新;按钮未写 type="submit"。
html
<form @submit.prevent="handleSubmit">
<button type="submit">登录</button>
</form>二、v-model 双向绑定:让数据和输入框同步
为什么需要:登录需要拿到用户输入,手动监听 input 再赋值很繁琐。
怎么想:输入框显示什么由数据决定,用户输入又写回数据,形成双向绑定。
怎么做:v-model="form.username",提交时直接读 form.username。
易错点:只写 :value 不写 v-model,输入不更新;v-model 绑定的对象层级写错;密码框忘记 type="password"。
三、name 属性:收集的 key 要与接口文档对应
为什么需要:提交给后端的字段名必须和接口文档一致,否则后端收不到。
怎么想:name 不是给人看的标题,而是数据键名。先看接口文档要求 username 还是 userName,再写 name。
怎么做:name="username",并与 v-model 的字段、接口参数保持同一套命名。
易错点:前端写 name="user",接口要 username;大小写不一致;多个输入框 name 重复。
四、label:输入框的标题与可访问性
为什么需要:用户要知道每个框填什么;点击文字能聚焦输入框,体验更好。
怎么想:label 是标题,不是占位提示。标题应长期可见,提示语只是辅助。
怎么做:<label for="username">用户名</label> 配合 <input id="username">,for 与 id 对应。
易错点:只写文字不写 for;for 和 id 不一致;把 label 当 placeholder 用。
五、:rules:表单校验规则
为什么需要:登录不能等接口报错才发现必填、格式问题,前端要先校验。
怎么想:规则要围绕字段名配置,:rules 绑定规则对象,表单项通过 prop 找到对应规则。
怎么做:在组件库表单中写 :rules="rules",规则里配置 required、message、trigger 等。
易错点:规则字段名和 prop 不一致;只写 rules 没写 prop;提交时忘记调用校验方法。
六、placeholder:提示语不是标题
为什么需要:提示用户输入格式,例如“请输入手机号”。
怎么想:placeholder 输入后消失,不能承担字段标题职责。
怎么做:placeholder="请输入用户名",简洁说明输入内容。
易错点:把必填说明全放占位符;提示语与 label 重复;密码框提示“请输入密码”却未说明规则。
七、调试与易错点汇总
转写稿里“错误看页面控制台,不要只盯终端”的习惯可以直接迁移:登录提交失败时,先看控制台报错、网络请求参数和接口文档字段名。重点检查三组对应关系:v-model 字段、name 字段、接口文档字段是否一致;label for 与 input id 是否一致;:rules 的 key 与表单项 prop 是否一致。提交入口统一用 @submit.prevent,不要只写按钮点击。这样登录表单的细节才不容易散。
本节目标与转写稿说明
本节要完成注册页的静态布局:先把页面骨架、表单字段、校验规则、提交入口和登录跳转搭好,提交逻辑暂时只打印表单值。需要说明的是,提供的转写稿主要围绕购物车、Vuex、项目安装等内容,未包含“注册静态布局”的推导和调试记录;因此下面不虚构调试过程,只依据 Register.vue 笔记代码展开。本节笔记没有图片资源,故不添加图片占位。
页面骨架:NavBar 与页面容器
为什么需要:注册页首先要有明确的页面标题和内容容器,否则后续表单元素没有稳定的布局落点。怎么想:用 van-nav-bar 承担顶部标题,外层 div.login-page 作为页面容器,表单和登录链接都放在容器内。怎么做:写入 <van-nav-bar title="面经注册" />,下面接 van-form。易错点:van-nav-bar 是 Vant 组件,项目需已引入 Vant;标题写在 title 属性中,不要写成普通文本节点。
表单容器:van-form 与提交入口
为什么需要:注册页需要统一收集用户名、密码,并在提交时做校验。怎么想:用 van-form 包住所有字段,把提交事件统一挂在表单上,而不是散落在按钮上。怎么做:写 <van-form @submit="onSubmit">,在 methods 中定义 onSubmit(values),先 console.log('submit', values) 观察提交值。易错点:@submit 要写在 van-form 上;values 是表单收集到的对象,字段名由 name 决定,所以每个 van-field 都要写 name。
用户名/密码字段与 v-model
为什么需要:输入框既要显示用户输入,又要让脚本拿到值,必须做双向绑定。怎么想:用户名和密码都用 v-model 绑定到 data 中的 username、password;密码额外设置 type="password" 隐藏输入。怎么做:用户名 van-field 写 v-model="username" name="username" label="用户名" placeholder="用户名";密码同理,并加 type="password"。易错点:v-model 绑定的变量必须在 data 中初始化;name 不要漏,否则提交对象里的字段名不符合预期;密码框不要忘记 type="password"。
校验规则:required 与 pattern
为什么需要:静态布局阶段就把前端校验挂上,能提前暴露空值和格式问题。怎么想:用 Vant 的 rules 数组,一条规则管必填,一条规则管格式。怎么做:用户名规则为 { required: true, message: '请填写用户名' } 和 { pattern: /^\w{5,}$/, message: '用户名至少包含5个字符' };密码规则为必填和 /^\w{6,}$/,提示“密码至少包含6个字符”。易错点:rules 是数组,不要写成对象;pattern 是正则,不是字符串;\w 表示字母、数字、下划线,并不等价于“任意字符”;两条规则是并列关系,空值时也会触发格式规则,实际提示以组件校验顺序为准。
提交按钮:native-type 的关键
为什么需要:按钮要真正触发 van-form 的提交事件,而不是只做样式展示。怎么想:van-button 的 type="primary" 控制按钮视觉样式,原生提交行为要用 native-type="submit"。怎么做:写 <van-button block type="primary" native-type="submit">注册</van-button>,外层用 style="margin: 16px" 留出间距。易错点:不要写成 type="submit",那会改变按钮样式语义;block 让按钮占满一行;按钮必须在 van-form 内部,否则提交事件不会按表单流程触发。
登录跳转与样式
为什么需要:注册页通常要提供“已有账号去登录”的入口。怎么想:用 router-link 做前端路由跳转,目标为 /login;用 scoped less 写局部样式。怎么做:写 <router-link class="link" to="/login">有账号,去登录</router-link>,样式设置颜色、字号、右内边距和右浮动。易错点:to 指向的路由必须已配置;float: right 可能影响父容器高度,后续若布局异常可考虑清除浮动或改用 flex;scoped 只作用于当前组件,类名要写对。
完整代码
jsx
<template>
<div class="login-page">
<van-nav-bar title="面经注册" />
<van-form @submit="onSubmit">
<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="primary" native-type="submit"
>注册</van-button
>
</div>
</van-form>
<router-link class="link" to="/login">有账号,去登录</router-link>
</div>
</template>
<script>
export default {
name: 'Register-Page',
data () {
return {
username: '',
password: ''
}
},
methods: {
onSubmit (values) {
console.log('submit', values)
}
}
}
</script>
<style lang="less" scoped>
.link {
color: #069;
font-size: 12px;
padding-right: 20px;
float: right;
}
</style>易错点汇总
先检查 Vant 组件是否可用;再检查 v-model 变量是否在 data 中;然后检查每个字段是否有 name;最后确认提交按钮使用 native-type="submit"、表单使用 @submit。静态阶段不写接口请求是合理的,onSubmit 只打印 values 便于后续接注册接口。
课件图示








代码示例
1. 注册页静态布局(Register.vue)
vue
<template>
<div class="login-page">
<van-nav-bar title="面经注册" />
<van-form @submit="onSubmit">
<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="primary" native-type="submit"
>注册</van-button
>
</div>
</van-form>
<router-link class="link" to="/login">有账号,去登录</router-link>
</div>
</template>
<script>
export default {
name: 'Register-Page',
data () {
return {
username: '',
password: ''
}
},
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="onSubmit":点击带native-type="submit"的按钮时自动触发 submit 事件,表单校验通过后才会执行;按钮漏写native-type="submit"就永远进不了onSubmit。v-model="username"/v-model="password":双向绑定,data里必须先声明这两个字段的初始值,否则绑定不生效。name="username"/name="password":这是提交时收集的 key,必须和接口文档的字段名对应,写错了后端收不到参数。label="用户名":输入框的标题;placeholder="用户名":输入框的提示语,两者是不同属性,不要混用。:rules="[...]":冒号不能省,省了就是普通字符串;required: true管必填,pattern: /^\w{5,}$/是正则,{5,}表示至少 5 个字符,正则不要加引号。type="password":密码框必须加,否则输入内容明文显示。onSubmit(values):形参values是{ username, password }对象,就是按各van-field的name收集来的。.link用了float: right,父容器会塌陷,若布局异常需自行清除浮动;scoped保证样式只作用于当前组件。
常见错误
- 现象:表单提交后
values字段名与接口不一致。→ 原因:name属性未按接口文档核对。→ 修法:逐项核对name,提交前打印values验证。 - 现象:点击“注册”没有触发表单校验/提交。→ 原因:按钮未设
native-type="submit"或van-form未绑定@submit。→ 修法:补齐@submit="onSubmit"与native-type="submit"。 - 现象:输入后校验提示不对或校验不到值。→ 原因:
v-model字段与data声明、rules配置不一致。→ 修法:统一字段名,按字段分别配置required/pattern。 - 现象:购物车加减后页面变了,刷新又恢复。→ 原因:只改 Vuex
state,未请求服务器持久化。→ 修法:action中先发PATCH,再commit mutation改本地状态。 - 现象:更新数量时改错商品或只传
count。→ 原因:缺少唯一标识id。→ 修法:传{ id, count },按id查找后更新。 - 现象:数量能减到 0 或负数。→ 原因:未做边界判断。→ 修法:
n === -1 && item.count === 1时直接返回。 - 现象:
json-server启动后端口/数据异常。→ 原因:终端当前路径找不到目标json文件。→ 修法:补全文件路径,或先cd到对应目录再启动。 - 现象:终端报错后反复重启,问题仍存在。→ 原因:主要错误应看浏览器控制台,终端不是首要排查入口。→ 修法:改代码并保存,以页面/控制台报错为准。
练习
- 在
Register.vue中完善用户名、密码校验:用户名至少 5 位、密码至少 6 位;提交时打印values,并检查name是否与接口文档一致。 - 实现购物车加减:点击
+/-调用同一方法并传±1;当数量为 1 时禁止继续减,说明最终传给 action 的参数结构。 - 完成
updateCountaction:要求先更新服务器数据,再通过 mutation 更新 Vuex 数据,并说明为什么不能只改 state。 - 用 getters 计算购物车总数量和总价格,并在 Footer 组件中用
mapGetters使用;说明mapGetters应放在哪个选项里。 - 模拟从项目根目录启动
cut.json失败,给出两种修复方式,并说明判断终端路径是否正确的依据。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 购物车-渲染数据 | 10:13 |
| 2 | 购物车-点击加号减号 | 08:57 |
| 3 | 购物车-更新数量 | 12:03 |
| 4 | 购物车-总数量和总价格 | 06:31 |
| 5 | vuex小结 | 09:22 |
| 6 | 安装新项目 | 10:12 |
小结
- 表单字段
name与接口文档一致,是提交数据可用的前提。 - 表单校验生效依赖
van-form @submit与提交按钮类型正确。 - Vuex 中改
state走mutation,接口请求与异步逻辑放action。 - 购物车数量更新要同时处理服务器持久化和本地状态,且必须携带
id + count。 - 数量边界判断和循环
key使用唯一id,是购物车稳定性的关键。 - 总数量、总价格适合用 getters,组件侧用
mapGetters并放在computed。 json-server启动以终端路径能准确找到 json 文件为准,排查优先看浏览器控制台。- 新项目脚手架按文档选型,组件库引入后先用简单按钮做验证。