主题
Vue 快速上手与指令(上)(四)
本页对应 Vue 快速上手与指令(上),共 6 段视频,约 46 分钟。
学习目标
- 能使用
v-for完成小黑记事本列表渲染,正确绑定唯一key,并展示“索引+1”的序号和任务名称。 - 能使用
v-model双向绑定输入框,点击添加时向数组新增包含唯一id和name的对象,并在添加后清空输入框。 - 能通过点击事件传递
id并完成删除功能,使用filter删除指定任务且保持其余数据不变。 - 能使用
list.length完成底部统计,并通过将数组置空实现清空任务,验证页面随数据变化自动更新。 - 能说明本案例中增删清空均通过修改数据完成,不直接操作 DOM,并能正确区分
v-if、v-show、v-bind、v-on、v-model的基本用法。
知识点
案例目标与数据准备
这个案例叫“小黑的书架”,目标很明确:左侧/数据区准备好书籍数组,右侧列表根据数组渲染出来;每行有一个“删除”按钮,点击后把当前这本书从列表中移除。效果如下:

为什么需要先准备数据?因为 Vue 的核心思路是“数据驱动视图”,列表不是手写死的,而是由 booksList 渲染出来的。怎么想?先把书做成对象数组,每本书有唯一 id、书名 name、作者 author。怎么做?保留给定准备代码:
html
<div id="app">
<h3>小黑的书架</h3>
<ul>
<li>
<span>《红楼梦》</span>
<span>曹雪芹</span>
<button>删除</button>
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
booksList: [
{ id: 1, name: '《红楼梦》', author: '曹雪芹' },
{ id: 2, name: '《西游记》', author: '吴承恩' },
{ id: 3, name: '《水浒传》', author: '施耐庵' },
{ id: 4, name: '《三国演义》', author: '罗贯中' }
]
}
})
</script>易错点:booksList 必须写在 data 里,模板里才能用;每本书的 id 不要重复,后面删除要靠它定位。
用 v-for 渲染书架列表
为什么需要 v-for?因为有多条书籍数据,不能一条条手写 <li>。怎么想?把静态的 <li> 改成循环项,循环 booksList,每一项叫 item。怎么做?在 <li> 上加 v-for="item in booksList",并给 :key="item.id",内容用插值表达式:
html
<ul>
<li v-for="item in booksList" :key="item.id">
<span>{{ item.name }}</span>
<span>{{ item.author }}</span>
<button>删除</button>
</li>
</ul>转写稿里提到“循环遍历数据就可以了”“有 ID 优先用 ID,因为 ID 不重复”,这里正好用 item.id 做 key。易错点:v-for 不要写成 v-for="item in booksList" 之外的花样;key 要写在循环项上;模板里访问数据不要写 this.booksList,直接写 booksList。
给删除按钮绑定点击事件并传 id
为什么需要传 id?因为点击某一行的删除按钮时,方法要知道“删哪一本”。怎么想?按钮点击时调用删除方法,把当前项的 item.id 传过去。怎么做?用 @click="del(item.id)":
html
<button @click="del(item.id)">删除</button>然后在 Vue 实例里写 methods,注意 methods 与 data 平级:
js
methods: {
del(id) {
this.booksList = this.booksList.filter(item => item.id !== id)
}
}转写稿里调试时说“点击的时候调一个方法,并且传递那个 ID”“方法千万不要写错位置,一定要和 data 平级”,这就是关键。易错点:@click="del(item.id)" 不要漏括号;方法名要和模板一致;不要写成 @click="del" 导致拿不到 id。
用 filter 按 id 过滤删除
为什么用 filter?因为删除的本质是“保留 id 不等于当前 id 的项”,生成一个新数组再赋值回去。怎么想?filter 会遍历数组,返回满足条件的元素组成新数组。怎么做?写 this.booksList = this.booksList.filter(item => item.id !== id)。转写稿里也是这个思路:“filter 然后 item.id !== id”,并且“箭头函数返回一个”。易错点:不要只写 this.booksList.filter(...) 而不赋值,否则页面不会变;比较要用 !==;箭头函数参数别漏;删除后 Vue 会响应式更新列表。
完整代码与调试检查
把上面拼起来:
html
<div id="app">
<h3>小黑的书架</h3>
<ul>
<li v-for="item in booksList" :key="item.id">
<span>{{ item.name }}</span>
<span>{{ item.author }}</span>
<button @click="del(item.id)">删除</button>
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
booksList: [
{ id: 1, name: '《红楼梦》', author: '曹雪芹' },
{ id: 2, name: '《西游记》', author: '吴承恩' },
{ id: 3, name: '《水浒传》', author: '施耐庵' },
{ id: 4, name: '《三国演义》', author: '罗贯中' }
]
},
methods: {
del(id) {
this.booksList = this.booksList.filter(item => item.id !== id)
}
}
})
</script>调试时先看列表是否渲染出 4 条,再点某行删除,确认对应行消失、其他行保留。易错点:methods 拼写、data 与 methods 层级、this.booksList 赋值、key 使用,都是本案例最常见的问题。
为什么需要 key
为什么需要: v-for 渲染列表时,Vue 默认会尽量“就地复用”已有元素,而不是把整个列表推倒重来。这样性能更好,但如果列表项顺序变化、插入或删除,复用就可能对应错元素。key 的作用就是给每个列表项一个唯一标识,让 Vue 能正确排序和复用。
怎么想: 转写稿里做小黑记事本时,列表用 v-for 循环 list,删除时传 id,添加时新增对象也要有 id。这说明列表项不是随便一段文字,而是有身份的数据。既然数据有 id,渲染时就应该把 id 交给 key,让 Vue 知道“谁是谁”。
怎么做: 在 v-for 的标签上写 :key="item.id"。注意是 :key,不是普通 key。因为 item.id 是变量表达式,要用 v-bind 绑定。笔记里的语法写作 key="唯一值",实际案例中应写成 :key="item.id"。
易错点: 不要写成 key="item.id",那样只是字符串;也不要见到属性就加冒号,转写稿总结里特别说:key 后边是变量才加冒号,class 后边不是变量就不加冒号。
语法与案例
为什么需要: 只写 v-for 能渲染,但列表项缺少稳定身份。加上 key 后,删除、插入、排序时 Vue 才能按标识匹配。
怎么想: key 的值只能是字符串或数字,并且必须唯一。最推荐用数据里的 id,因为 id 不重复;不推荐用 index,因为索引会随着插入、删除变化,不能稳定对应原数据。
怎么做: 保留笔记中的代码:
js
<ul>
<li v-for="(item, index) in booksList" :key="item.id">
<span>{{ item.name }}</span>
<span>{{ item.author }}</span>
<button @click="del(item.id)">删除</button>
</li>
</ul>这里的 :key="item.id" 就是给每个 li 绑定唯一标识;删除按钮传 item.id,删除方法才能准确找到要删的那一项。
易错点: key 不要重复;不要用会变化的 index 当唯一标识;key 的值类型要稳定,不能一会儿数字一会儿对象。
结合小黑记事本看 key 的调试过程
为什么需要: 转写稿的案例能帮助理解:列表渲染、删除、添加都围绕“唯一标识”展开。没有稳定 id,删除和复用都容易对不上。
怎么想: 视频里先循环 list,写 item, index,然后给 li 加 :key="item.id",并强调“有 ID 来说呢,是不是优先用 ID 啊?因为 ID 是不重复的”。删除时调 del(item.id),方法里用 filter 保留 item.id !== id 的项。添加时不能直接 unshift(this.name),否则新数据只有光秃秃的名字,格式和原数据不一致;要新增 { id: ..., name: this.name }。
怎么做: 删除逻辑可写成 this.list = this.list.filter(item => item.id !== id);添加时 id 用时间戳,转写稿提到 +new Date() 或 Date.now(),因为时间戳随时间变化,不容易重复。添加完再清空输入框:this.name = ''。
易错点: 新增对象的 id 不能写死,否则第二次添加会重复;也不能随便随机,因为随机仍可能撞值。key 重复会让复用判断出问题。转写稿还提醒:新增数据格式要和原数据一致,原来有 id、name,新增也要有。
易错点汇总
为什么需要: key 写错不会总是立刻报错,但会在列表更新时埋下隐患。
怎么想: 记住三句话:唯一、稳定、用 id。index 虽然也是数字,但会变化,所以不推荐。
怎么做: 列表项有 id 就用 :key="item.id";删除传 id;添加生成不重复 id。
易错点: 第一,key 的值只能是字符串或数字;第二,必须唯一;第三,推荐 id,不推荐 index;第四,绑定变量别漏冒号。
双向绑定:让数据和页面互相“通电话”
前面学的插值表达式、v-text、v-html 都是单向的:数据变了,页面跟着更新。但表单元素有个特殊之处——它的值可以由用户在页面上直接改动。如果只靠单向渲染,用户在输入框里敲的内容就进不了 data,我们在代码里也就拿不到。
为什么需要:笔记给的定义是两条——数据改变后,呈现的页面结果会更新;页面结果更新后,数据也会随之而变。前一条我们已经在响应式里体验过了,后一条正是表单场景的刚需。
怎么想:把输入框的值和 data 里的某个变量“绑”在一起,谁变另一边都跟着变,就不用再手动去 document.querySelector 取 value 了。
怎么做:v-model="变量"。
易错点:v-model 只能用在表单元素上。转写稿里讲师说得很直白:只有表单元素才能在页面中改值,输入框你才能在上面改东西,一个 p 标签你怎么改,没法改。所以给 p、div 加 v-model 是没有意义的。
v-model 的语法和适用范围
语法:v-model="变量"
作用:给表单元素(input、radio、select)使用,双向绑定数据,可以快速获取或设置表单元素内容。
转写稿里提到,这一节先讲基本使用(文本框),复选框、下拉列表怎么用 v-model,后面再继续说。
易错点:
- 变量必须在
data中声明。模板里用到的数据,data中必须有,否则绑不上,这跟前面对插值表达式的要求是一致的。 - 不要把
v-model和:value混为一谈。:value是v-bind,只做单向的数据到页面。 - 双向绑定能“设置”表单内容,靠的就是改数据:把变量改成什么,输入框里就显示什么。
案例需求:登录表单的获取与重置
需求:
- 点击登录按钮获取表单中的内容
- 点击重置按钮清空表单中的内容

笔记给出的初始结构如下,两个输入框和两个按钮,data 里已经准备好了 username 和 password:
js
<div id="app">
账户:<input type="text"> <br><br>
密码:<input type="password"> <br><br>
<button>登录</button>
<button>重置</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
username: '',
password: ''
},
})
</script>把 v-model 和点击事件补上
怎么想:既然 v-model 已经把输入框和变量绑在一起,那么“获取表单内容”就不需要再去读 DOM,直接读 this.username、this.password 就行;“清空表单”也不是去操作输入框,而是把这两个变量赋成空字符串,页面会自己变空。
怎么做:两个输入框分别加上 v-model,两个按钮分别加上点击事件,事件处理函数写在 methods 里。
html
<div id="app">
账户:<input type="text" v-model="username"> <br><br>
密码:<input type="password" v-model="password"> <br><br>
<button @click="login">登录</button>
<button @click="reset">重置</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
username: '',
password: ''
},
methods: {
login() {
console.log(this.username, this.password)
},
reset() {
this.username = ''
this.password = ''
}
}
})
</script>易错点:methods 必须和 el、data 平级,不要嵌套进 data 里面写错位置;@click 后面跟的是方法名,方法要定义在 methods 中,两边名字要对得上。
用调试工具验证绑定是否真的通了
转写稿里演示了一个很实用的验证过程:写好 v-model 之后,打开浏览器的调试工具查看 Vue 实例的数据,能看到 data 里确实有这个变量;接着在输入框里敲内容,比如输入“吃饭”,就能看到下边这个变量的值同步变成了“吃饭”——说明输入框的值已经被拿到了。
这个调试动作值得养成习惯:绑定没生效时,先看变量在不在、值有没有随输入变化,能快速判断是 v-model 写错了,还是变量根本没在 data 里声明。
重置为什么只改数据就够了
转写稿里在讲记事本添加功能时提到过清空输入框的做法:让 this.name 等于空,这就是修改数据,输入框随之变空。这正是双向绑定“反向”的那一半在起作用。
怎么想:单向渲染时,要清空输入框得拿到 DOM 元素再改 value;有了双向绑定,数据是源头,改数据就是改页面。
易错点:重置时要把每个绑定的变量都置空,漏掉一个,对应的输入框就不会清空;另外不要写成 this.username == '',那是比较,不是赋值。
小结
v-model 是 Vue 响应式特性在表单上的直接体现:页面改值,数据跟着变;数据改值,页面跟着变。用它之后,获取和设置表单内容都变成了“读变量”和“写变量”这两件最简单的事。
案例总览:四个功能串成一条线

这一节用一个完整的小案例把前面学的指令串起来,做出“小黑记事本”。它要完成四件事:
- 列表渲染
- 删除功能
- 添加功能
- 底部统计 和 清空
页面结构分三块:头部是一个 input 输入框加“添加任务”按钮;中间是 ul 列表区,li 里放序号、任务名称和删除按钮;底部是统计区和“清空任务”按钮。数据区已经准备好一个 list 数组,三条数据,每条都是 { id, name } 形式的小对象。
列表渲染:用 v-for 把数组铺到页面上
为什么需要:模板里的 li 是静态写死的,只有一条。真实场景里任务数量不固定,写死就没法增删,必须让页面跟着数据走。
怎么想:既然数据在 list 数组里,就让 li 循环遍历这个数组,数组有几条就渲染几个 li。序号用索引,名称用 item.name。
怎么做:
html
<li v-for="(item, index) in list" :key="item.id">
<span>{{ index + 1 }}</span>
<span>{{ item.name }}</span>
<button class="del" @click="del(item.id)">×</button>
</li>易错点:一是 :key 优先用 id 而不是索引,因为 id 不会重复;二是索引从 0 开始,页面上要的是 1、2、3,所以必须写 index + 1,这一点在刷新页面对比 012 和 123 时最容易发现。
删除功能:点击后把这一条过滤掉
为什么需要:列表能显示还不够,用户要能删掉不想要的任务。
怎么想:不需要操作 DOM,只改数据。点击时把这条的 id 传出去,在数组里把 id 相同的那条筛掉,数据一变页面自动更新,这就是响应式。
怎么做:
html
<button class="del" @click="del(item.id)">×</button>js
methods: {
del(id) {
this.list = this.list.filter(item => item.id !== id)
}
}易错点:方法必须写在 methods 里,并且和 data 平级,转写稿里反复强调“千万不要写错位置”,写进 data 里就调不到。另外 filter 返回的是新数组,必须重新赋值给 this.list,只调用不接收是没有效果的。
添加功能:v-model 收集输入,unshift 插入
为什么需要:记事本得能记录新任务,所以要把输入框里用户敲的内容拿到手。
怎么想:拿输入框的值用 v-model 做双向绑定最省事,输入什么,data 里的变量就跟着变;点“添加任务”时,往 list 里插一条新数据,页面自然多一行。
怎么做:data 里加一个 name: '',输入框绑上 v-model="name",按钮绑 @click="add":
html
<input v-model="name" type="text">
<button @click="add">添加任务</button>js
data() {
return {
list: [...],
name: ''
}
},
methods: {
add() {
this.list.unshift({
id: Date.now(),
name: this.name
})
this.name = ''
}
}易错点(也是转写稿里的调试过程):一开始图省事写成 this.list.unshift(this.name),结果数组里多了“光秃秃的两个字”,和原来 { id, name } 的格式对不上,所以新增的也必须是对象。id 不能写死,比如固定写 23,加第二次就重复了;随机数也可能撞车;用时间戳 Date.now() 或 +new Date() 最稳,它随时间一直变化,不会重复。还有个小细节:添加完输入框没清空,得补一句 this.name = ''。用 unshift 是插到最前面,新任务显示在顶部,和原案例一致。
底部统计和清空
为什么需要:用户要一眼看到还剩几条记录,也需要一键清空。
怎么想:统计就是数组长度,清空就是把数组变成空数组,两件事都短到不用单独写方法。
怎么做:
html
<span>合计:{{ list.length }}</span>
<button @click="list = []">清空任务</button>易错点:内联写法里只能用 Vue 提供的数据和方法,写 console.log 这类是不行的;写长了还是老老实实抽到 methods 里。
小结
整个案例没有一行 DOM 操作,全靠“改数据 → 视图自动更新”这一条思路。渲染靠 v-for,删除靠 filter 重新赋值,添加靠 v-model 收集加 unshift 插入,统计和清空直接读长度、赋空数组。把这四步走顺,指令部分就算真正落地了。
课件图示








代码示例
1. 小黑的书架:v-for 渲染 + key + 删除
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>小黑的书架</title>
</head>
<body>
<div id="app">
<h3>小黑的书架</h3>
<ul>
<li v-for="(item, index) in booksList" :key="item.id">
<span>{{ item.name }}</span>
<span>{{ item.author }}</span>
<button @click="del(item.id)">删除</button>
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
booksList: [
{ id: 1, name: '《红楼梦》', author: '曹雪芹' },
{ id: 2, name: '《西游记》', author: '吴承恩' },
{ id: 3, name: '《水浒传》', author: '施耐庵' },
{ id: 4, name: '《三国演义》', author: '罗贯中' }
]
},
methods: {
del(id) {
this.booksList = this.booksList.filter(item => item.id !== id)
}
}
})
</script>
</body>
</html>要点解释与易错点:
v-for="(item, index) in booksList"用于循环渲染书籍列表。:key="item.id"推荐使用唯一id,不推荐用index作为 key。- 删除按钮通过
@click="del(item.id)"把当前行id传给方法。 filter返回新数组,再赋值给booksList,从而实现删除并触发视图更新。- 易错点:
filter条件应写item.id !== id,不要直接修改原数组造成不可控问题。
2. 双向绑定:登录与重置
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>双向绑定</title>
</head>
<body>
<div id="app">
账户:<input type="text" v-model="username"> <br><br>
密码:<input type="password" v-model="password"> <br><br>
<button @click="login">登录</button>
<button @click="reset">重置</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
username: '',
password: ''
},
methods: {
login() {
console.log(this.username, this.password)
},
reset() {
this.username = ''
this.password = ''
}
}
})
</script>
</body>
</html>要点解释与易错点:
v-model="username"、v-model="password"实现表单元素与数据的双向绑定。- 数据改变页面会更新;页面输入改变,数据也会随之改变。
- 登录时通过
this.username、this.password获取表单内容。 - 重置时直接把数据赋值为空字符串,页面输入框会自动清空。
- 易错点:
v-model主要用于表单元素;不要忘记在data中初始化变量。
3. 小黑记事本:列表渲染、删除、添加、统计、清空
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>小黑记事本</title>
</head>
<body>
<div id="app">
<header>
<input type="text" v-model="name" placeholder="请输入任务">
<button @click="add">添加任务</button>
</header>
<ul>
<li v-for="(item, index) in list" :key="item.id">
<span>{{ index + 1 }}.</span>
<span>{{ item.name }}</span>
<button @click="del(item.id)">×</button>
</li>
</ul>
<footer>
合计:{{ list.length }} 条
<button @click="list = []">清空任务</button>
</footer>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
list: [
{ id: 1, name: '吃饭' },
{ id: 2, name: '睡觉' },
{ id: 3, name: '打豆豆' }
],
name: ''
},
methods: {
add() {
this.list.unshift({
id: Date.now(),
name: this.name
})
this.name = ''
},
del(id) {
this.list = this.list.filter(item => item.id !== id)
}
}
})
</script>
</body>
</html>要点解释与易错点:
- 输入框使用
v-model="name"获取任务名称。 - 添加任务时用
unshift把新任务加到数组前面,并且新增数据要保持对象格式:{ id, name }。 id使用Date.now(),避免使用随机数或固定值导致重复。- 添加完成后执行
this.name = ''清空输入框。 - 删除使用
filter按id过滤;统计直接使用list.length;清空直接让list = []。 - 易错点:不要只把
this.name字符串直接加入数组,否则会破坏原有数据结构;v-for的:key推荐使用唯一id。
常见错误
1. 新增任务时直接把输入框的字符串放进数组
- 现象:点击添加后,新行只显示文字,作者、序号等字段全部为空,模板里
item.name取不到值。 - 原因:只想着“让数组多一条”,忘了数组元素必须和原有数据保持同样的对象结构。
- 修法:新增时构造完整对象
{ id: Date.now(), name: this.name },保证字段和已有数据对齐。
2. 新增数据的 id 用 index、随机数或写死的数字
- 现象:连续添加几次后再删除,删掉的不是点中的那一行,或者一次删掉多行。
- 原因:id 不唯一,
filter的比较条件同时命中了多条记录,key也失去区分度。 - 修法:用时间戳生成 id(
Date.now()或+new Date()),它随时间递增,天然不重复。
3. filter 里用了花括号却忘记 return
- 现象:点一次删除,整个列表被清空。
- 原因:
item => { item.id !== id }的函数体返回undefined,被当作 false,所有元素都被过滤掉。 - 修法:去掉花括号写成
item => item.id !== id,或在花括号内补return。
4. 添加成功后没有清空输入框
- 现象:连续点击添加会重复插入同一内容,用户以为没生效。
- 原因:只处理了“写入数组”,漏掉了“重置表单数据”。
- 修法:在 add 方法末尾补
this.name = '',靠双向绑定自动清空视图。
5. v-model 绑定了 data 里没声明的变量,或绑到了非表单元素上
- 现象:输入框打字没反应,或控制台报属性未定义。
- 原因:
v-model只对 input、radio、select 等表单元素有效,且绑定的变量必须先在 data 中初始化。 - 修法:data 里先写
name: '',再在 input 上写v-model="name"。
6. 内联事件里写了 Vue 之外的东西
- 现象:
@click="console.log(1)"直接报错。 - 原因:内联语句的作用域是 Vue 实例,只能用实例上的数据和方法,
console不在其中。 - 修法:逻辑超过一行或需要外部 API 时,抽成 methods 里的方法再调用。
7. key 用了 index
- 现象:列表项里放输入框时,删掉中间一项后,后面几行的输入内容“串行”了。
- 原因:index 会随删除而变化,无法稳定标识同一行,Vue 复用时把状态错配给了别的元素。
- 修法:改用
:key="item.id"。
练习
练习 1|书架空态 在小黑的书架案例中补两点:删除前用 confirm 二次确认;当 booksList.length === 0 时,列表区显示“书架空空如也”,否则正常渲染。
练习 2|添加校验 记事本的添加功能加上校验:输入内容 trim() 后为空则不插入,并给出提示;非空时正常插入到列表最前面,随后清空输入框。
练习 3|key 对比实验 把列表项结构改成“一个输入框 + 删除按钮”,先用 :key="index" 运行,在几个输入框里写不同内容后删除第二项,记录现象;再把 key 换成 item.id 重做一遍,用一句话写出两次结果差异的原因。
练习 4|完成任务 给每条记录加 done: false 字段,列表项前置一个复选框用 v-model="item.done" 绑定,已完成项文字加删除线;底部统计改为“共 X 条 / 已完成 Y 条”。
练习 5|按条件清空 把“清空任务”按钮改为“清空已完成”,点击后只移除 done 为 true 的记录,未完成的保留,并验证统计数字同步变化。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 案例-小黑记事本-列表渲染 | 05:15 |
| 2 | 案例-小黑记事本-删除功能 | 02:22 |
| 3 | 案例-小黑记事本-添加功能 | 11:31 |
| 4 | 案例-小黑记事本-底部统计和清空 | 01:44 |
| 5 | 总结 | 15:03 |
| 6 | 获取资料和作业 | 11:00 |
小结
- 列表类需求的统一套路是:数据是唯一真相,增、删、改一律只动数组,视图交给响应式自动更新,全程不碰 DOM。
- 新增数据的正确性取决于“结构一致 + id 唯一”这两条,缺任何一条都会在渲染或删除环节暴露问题。
- 前端生成唯一 id,时间戳是成本最低的可靠方案;index、随机数、写死值都会在连续操作中失效。
filter的返回值直接决定删除结果,箭头函数简写与完整写法的差异必须心里有数。v-model的价值在于“取值”和“设值”共用一份数据,因此清空表单只需要给变量重新赋值。- key 不是用来消除警告的装饰品,它决定元素复用时状态归属于谁;能用 id 就不要用 index。
- 内联事件只适合一行以内的简单语句,涉及外部 API 或复杂逻辑一律下沉到 methods。
- 每个案例完成后都要跑边界:删中间项、连续添加、删到空、清空后再添加——正常流程往往掩盖问题。