vue-day02
目录
2指令修饰符
问题:
3v-bind
问题:
4v-model应用于其它表单元素
问题
5计算属性
问题
6成绩案例
7watch监视器-简写-语法
问题
8wathc完整版
问题
9水果购物车
问题
总结

2指令修饰符



问题:
1@keyup.enter就相当于 @keyup然后在绑定的方法里面加上if(e.key=='enter')判断才进行下一步操作
2v-model:双向绑定的数据默认是String类型,想要输入数值的话得使用v-model.number
3.stop可以阻止冒泡行为,就是如果内外两层甚至多层有同一个类似于鼠标点击事件的话,只会执行最内层的
4.prevetn是阻止默认行为,尝应用在@submit.prevent中,因为在传统的html的表单提交会默认导致页面刷新,而.prevent就是阻止默认行为的
3v-bind






问题:
第三张图片的@click是activeIndex=index(可以实现点击切换)
transition: all 1s//这可可以添加动画效果,如进度条不是直接变化,而是缓慢变化
4v-model应用于其它表单元素




问题
多个单选框怎么确定是同一范围的,使用相同的name=""来进行控制同一组别,使用value用于提交给后台数据,要不然表单不知道选择这个单选框要提交什么,同理select里面的option标签的value值也是如此
5计算属性






问题
在差值表达式中使用totalCount为什么不需要加()?
因为它是一个属性
reduce如何使用?
int total=this.list.reduce((sum,item)=>sum+item.num,0)//sum表示累加器,item表示正在处理的数组元素,=>{}里面是处理逻辑,最后面是初始值
6成绩案例



7watch监视器-简写-语法

![]()


问题
属性名要和上面相同
如果不是data的子对象,而是子对象的子属性,该怎么办?
一是绑定要换成 子对象.属性名,下面就是引号里面写这样即可
防抖操作,延时函数,另外还需要清空函数,要不然最后延时的结果还是会输出,加上清空就好多了
8wathc完整版



问题
因为watch是只有数据被修改才会执行,那么我想在一刷新浏览器就执行该怎么办?
immediate:true即可
9水果购物车











问题
item.isChecked是bool类型,在标签里面设置v-model=item.isChecked就是为true才绑定,同理:class="{active:item.isChecked}"也是这个意思(active是高亮显示)
:disabled="item.num<=1"可以设置当个数小于等于1的时候就禁止再按了
data属性里面fruitList后面加个||defaultArr
总结
上面看懂下面可以不看
Vue 核心知识点深度总结:从基础到实战的全面解析
在前端开发领域,Vue.js 凭借其易用性、灵活性和高效性,成为了开发者们青睐的框架之一。本文将围绕 Vue 的核心知识点,从指令、数据绑定、计算属性到实战案例,进行一次全面且深入的总结,帮助大家夯实 Vue 基础,提升实战能力。
一、课程介绍
Vue 是一款渐进式 JavaScript 框架,所谓 “渐进式”,意味着我们可以根据项目需求,逐步引入 Vue 的功能。它的核心库只关注视图层,易于上手,同时也能通过丰富的生态系统构建复杂的单页应用。
Vue 的核心优势在于:
响应式数据绑定:当数据发生变化时,视图会自动更新,无需手动操作 DOM。
组件化开发:将页面拆分为可复用的组件,提高代码的可维护性和复用性。
轻量级:体积小,加载速度快,性能出色。
丰富的生态:拥有 Vue Router(路由)、Vuex(状态管理)、Vue CLI(脚手架)等周边工具,能满足各种项目需求。
学习 Vue,我们可以从基础的指令、数据绑定开始,逐步深入到组件通信、状态管理,最后通过实战案例将知识融会贯通。
二、指令修饰符
Vue 指令是带有v-前缀的特殊属性,它们提供了便捷的 DOM 操作和数据响应式能力。而指令修饰符则是对指令功能的扩展,以.的形式附加在指令后面,用于处理一些常见的场景,让代码更加简洁高效。
2.1 事件修饰符
在v-on(简写为@)指令中,事件修饰符可以帮助我们处理事件的冒泡、默认行为等。
.stop:阻止事件冒泡。例如,在一个嵌套的元素中,点击子元素时,父元素的点击事件不会触发。
vue
<div @click="parentClick">
<button @click.stop="childClick">点击我</button>
</div>
.prevent:阻止事件的默认行为,如表单提交的刷新页面。
vue
<form @submit.prevent="submitForm">
<button type="submit">提交</button>
</form>
.capture:使用事件捕获模式,即事件从外层元素向目标元素传播时触发。
.self:只有当事件是从当前元素本身触发时才会触发回调。
.once:事件只触发一次。
2.2 按键修饰符
用于监听键盘事件时,对特定按键进行过滤。
常见的按键别名:.enter、.tab、.delete(捕获 “删除” 和 “退格” 键)、.esc、.space、.up、.down、.left、.right。
vue
<input @keyup.enter="submit">
还可以自定义按键别名,通过Vue.config.keyCodes来设置。
2.3 表单修饰符
在v-model指令中,表单修饰符用于处理表单元素的数据绑定。
.lazy:将输入事件的同步时机从 “输入时” 改为 “失焦时”,减少数据更新的频率。
vue
<input v-model.lazy="msg">
.number:将输入的值转换为数字类型。如果输入的内容无法被解析为数字,就会返回原始的字符串。
vue
<input v-model.number="age" type="number">
.trim:自动过滤输入内容的首尾空格。
vue
<input v-model.trim="username">
三、v-bind
v-bind指令用于动态地绑定一个或多个属性,或者向组件传递 props。它的简写形式是:。
3.1 绑定 HTML 属性
可以绑定元素的任何 HTML 属性,如class、style、src、href等。
vue
<img :src="imageUrl" :alt="imageAlt">
<a :href="linkUrl">链接</a>
3.2 绑定 Class
绑定class有多种方式,非常灵活。
对象语法:根据对象的属性值是否为true,来决定是否添加对应的类名。
vue
<div :class="{ active: isActive, 'text-danger': hasError }"></div>
数组语法:可以将多个类名放在一个数组中进行绑定。
vue
<div :class="[activeClass, errorClass]"></div>
数组与对象语法结合:在数组中可以嵌套对象语法。
vue
<div :class="[{ active: isActive }, errorClass]"></div>
3.3 绑定 Style
绑定style同样支持对象语法和数组语法。
对象语法:直接将样式对象绑定到元素上。
vue
<div :style="{ color: textColor, fontSize: fontSize + 'px' }"></div>
数组语法:可以将多个样式对象数组合并。
vue
<div :style="[baseStyles, overridingStyles]"></div>
自动添加前缀:当绑定的 CSS 属性需要浏览器前缀时,Vue 会自动为其添加合适的前缀。
3.4 向组件传递 Props
在组件中,使用v-bind向子组件传递 props 数据。
vue
<child-component :message="parentMsg" :user="currentUser"></child-component>
四、v-model 应用于其它表单元素
v-model是 Vue 中用于实现表单元素双向数据绑定的指令,它不仅可以用于input、textarea、select等常见表单元素,还可以应用于一些自定义组件,实现数据的双向同步。
4.1 基本表单元素的 v-model
文本输入框(input [type="text"])和文本域(textarea):
vue
<input v-model="message" placeholder="请输入">
<textarea v-model="message" rows="3"></textarea>
单选按钮(input [type="radio"]):
vue
<input type="radio" id="male" value="male" v-model="gender">
<label for="male">男</label>
<input type="radio" id="female" value="female" v-model="gender">
<label for="female">女</label>
复选框(input [type="checkbox"]):
单个复选框,绑定布尔值:
vue
<input type="checkbox" id="agree" v-model="isAgree">
<label for="agree">同意协议</label>
多个复选框,绑定数组:
vue
<input type="checkbox" id="apple" value="apple" v-model="fruits">
<label for="apple">苹果</label>
<input type="checkbox" id="banana" value="banana" v-model="fruits">
<label for="banana">香蕉</label>
下拉选择框(select):
单选:
vue
<select v-model="selected">
<option value="">请选择</option>
<option value="vue">Vue</option>
<option value="react">React</option>
</select>
多选(绑定数组):
vue
<select v-model="selected" multiple>
<option value="vue">Vue</option>
<option value="react">React</option>
<option value="angular">Angular</option>
</select>
4.2 v-model 的原理
v-model实际上是v-bind和v-on的语法糖。对于输入框来说,大致等价于:
vue
<input :value="message" @input="message = $event.target.value">
其中,input事件是在输入框内容变化时触发的,将输入框的当前值赋值给message变量,从而实现双向绑定。
4.3 自定义组件的 v-model
在自定义组件中,可以通过model选项来定制v-model的 prop 和事件。默认情况下,自定义组件的v-model会使用value作为 prop,并以input事件作为触发事件。
vue
// 子组件
Vue.component('custom-input', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: `
<input
type="checkbox"
:checked="checked"
@change="$emit('change', $event.target.checked)"
>
`
})
// 父组件使用
<custom-input v-model="isChecked"></custom-input>
这样,在父组件中使用v-model时,就会将isChecked的值传递给子组件的checked prop,并且子组件触发change事件时,会更新isChecked的值。
五、计算属性
计算属性是 Vue 中用于处理复杂数据逻辑的重要工具,它基于响应式依赖进行缓存,只有当依赖的数据发生变化时,才会重新计算,从而提高性能。
5.1 基本用法
在 Vue 实例的computed选项中定义计算属性,它的使用方式和普通属性一样。
vue
<div id="app">
<p>原始消息: {{ message }}</p>
<p>反转后的消息: {{ reversedMessage }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
computed: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
})
</script>
在上面的例子中,reversedMessage是一个计算属性,它依赖于message的值。当message发生变化时,reversedMessage会自动重新计算。
5.2 计算属性的缓存 vs 方法
我们也可以通过方法来实现和计算属性相同的功能:
vue
<p>反转后的消息: {{ reverseMessage() }}</p>
<script>
methods: {
reverseMessage: function () {
return this.message.split('').reverse().join('')
}
}
</script>
但是,计算属性和方法的主要区别在于缓存。计算属性会根据其依赖的响应式数据进行缓存,只有当依赖变化时才会重新计算;而方法在每次调用时都会重新执行函数。因此,对于复杂的计算逻辑,使用计算属性可以提高性能。
5.3 计算属性的 setter
计算属性默认只有 getter,但我们也可以为其设置 setter,使其支持双向数据绑定。
vue
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
当我们对fullName进行赋值时,setter 会被调用,从而更新firstName和lastName的值。
5.4 计算属性的应用场景
计算属性适用于以下场景:
对现有数据进行格式化处理,如日期格式化、字符串拼接等。
根据多个数据的组合计算出一个新的值。
处理需要缓存的复杂逻辑,避免重复计算。
例如,在一个购物车页面中,我们可以使用计算属性来计算商品的总价:
vue
computed: {
totalPrice: function () {
return this.cartItems.reduce((total, item) => {
return total + item.price * item.quantity
}, 0)
}
}
六、成绩案例
为了更好地理解 Vue 的核心知识点,我们通过一个 “成绩案例” 来进行实战演练。这个案例主要实现一个学生成绩的录入、展示和统计功能,涉及到数据绑定、计算属性、表单处理等知识点。
6.1 需求分析
可以录入学生的姓名和各科成绩(数学、语文、英语)。
实时计算每个学生的总分和平均分。
可以删除学生信息。
统计所有学生的各科总分、平均分以及整体的总分和平均分。
6.2 代码实现
vue
<div id="app">
<h2>学生成绩管理系统</h2>
<form @submit.prevent="addStudent">
<div class="form-group">
<label>姓名:</label>
<input type="text" v-model="newStudent.name" placeholder="请输入姓名" required>
</div>
<div class="form-group">
<label>数学:</label>
<input type="number" v-model.number="newStudent.math" placeholder="请输入数学成绩" min="0" max="100" required>
</div>
<div class="form-group">
<label>语文:</label>
<input type="number" v-model.number="newStudent.chinese" placeholder="请输入语文成绩" min="0" max="100" required>
</div>
<div class="form-group">
<label>英语:</label>
<input type="number" v-model.number="newStudent.english" placeholder="请输入英语成绩" min="0" max="100" required>
</div>
<button type="submit">添加学生</button>
</form>
<table border="1" cellpadding="10" cellspacing="0">
<thead>
<tr>
<th>姓名</th>
<th>数学</th>
<th>语文</th>
<th>英语</th>
<th>总分</th>
<th>平均分</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(student, index) in students" :key="index">
<td>{{ student.name }}</td>
<td>{{ student.math }}</td>
<td>{{ student.chinese }}</td>
<td>{{ student.english }}</td>
<td>{{ student.total }}</td>
<td>{{ student.average }}</td>
<td><button @click="deleteStudent(index)">删除</button></td>
</tr>
</tbody>
<tfoot v-if="students.length > 0">
<tr>
<td>总计</td>
<td>{{ totalMath }}</td>
<td>{{ totalChinese }}</td>
<td>{{ totalEnglish }}</td>
<td>{{ totalAll }}</td>
<td>{{ averageAll }}</td>
<td></td>
</tr>
</tfoot>
</table>
</div>
<script>
new Vue({
el: '#app',
data: {
students: [],
newStudent: {
name: '',
math: 0,
chinese: 0,
english: 0
}
},
computed: {
totalMath: function () {
return this.students.reduce((total, student) => total + student.math, 0)
},
totalChinese: function () {
return this.students.reduce((total, student) => total + student.chinese, 0)
},
totalEnglish: function () {
return this.students.reduce((total, student) => total + student.english, 0)
},
totalAll: function () {
return this.totalMath + this.totalChinese + this.totalEnglish
},
averageAll: function () {
return (this.totalAll / (this.students.length * 3)).toFixed(2)
}
},
methods: {
addStudent: function () {
// 计算总分和平均分
const total = this.newStudent.math + this.newStudent.chinese + this.newStudent.english
const average = (total / 3).toFixed(2)
// 将新学生对象添加到students数组中
this.students.push({
...this.newStudent,
total: total,
average: average
})
// 清空表单
this.newStudent = {
name: '',
math: 0,
chinese: 0,
english: 0
}
},
deleteStudent: function (index) {
this.students.splice(index, 1)
}
}
})
</script>
<style>
.form-group {
margin-bottom: 10px;
}
label {
display: inline-block;
width: 50px;
}
input {
width: 150px;
padding: 5px;
}
button {
padding: 5px 10px;
cursor: pointer;
}
table {
margin-top: 20px;
}
</style>
6.3 代码解析
数据绑定:通过v-model实现表单元素与newStudent对象的双向绑定,方便数据的录入。
计算属性:使用计算属性来计算每个学生的总分、平均分以及所有学生的各科总计、整体平均分,这样当学生数据发生变化时,这些统计数据会自动更新。
列表渲染:通过v-for指令遍历students数组,展示每个学生的成绩信息。
事件处理:使用@submit.prevent阻止表单的默认提交行为,通过@click事件实现删除学生的功能。
这个案例综合运用了 Vue 的多个核心知识点,展示了如何将理论知识应用到实际项目中,实现一个具有实用功能的小应用。
七、watch 监视器 - 简写 - 语法
watch是 Vue 中用于监听数据变化的选项,它可以让我们在数据发生变化时执行相应的操作。除了完整的对象语法外,Vue 还提供了简写的语法,让代码更加简洁。
7.1 基本用法(简写)
当我们只需要在数据变化时执行一个函数,而不需要其他配置(如deep、immediate等)时,可以使用简写语法,直接将监听的属性名作为键,对应的处理函数作为值。
vue
<div id="app">
<input v-model="message">
<p>消息长度:{{ messageLength }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: '',
messageLength: 0
},
watch: {
// 简写语法,监听message的变化
message: function (newVal, oldVal) {
this.messageLength = newVal.length
}
}
})
</script>
在上面的例子中,当message的值发生变化时,watch中的处理函数会被调用,更新messageLength的值。
7.2 与计算属性的区别
watch和计算属性都可以用于处理数据变化,但它们的适用场景有所不同:
计算属性:适用于根据已有数据计算出一个新的数据,并且这个新数据会被多次使用的场景。它是响应式的,会自动更新。
watch:适用于数据变化时需要执行异步操作(如发送请求)、执行复杂的业务逻辑或需要获取数据变化前后的值的场景。
例如,当我们需要根据用户的输入去请求后端数据时,使用watch更为合适:
vue
watch: {
searchKeyword: function (newVal) {
// 发送异步请求
axios.get('/api/search', {
params: { keyword: newVal }
}).then(response => {
this.searchResults = response.data
})
}
}
7.3 注意事项
简写语法只能监听顶层属性的变化,对于嵌套对象或数组中的属性变化,需要使用完整的对象语法并设置deep: true。
在简写语法中,处理函数的第一个参数是新值(newVal),第二个参数是旧值(oldVal)。
八、watch 完整版
虽然简写语法在很多场景下已经足够使用,但在一些复杂的场景中,我们需要使用watch的完整版语法,来配置更多的选项,如deep(深度监听)、immediate(立即执行)等。
8.1 完整语法的结构
vue
watch: {
// 要监听的属性名
propertyName: {
// 处理函数,newVal是新值,oldVal是旧值
handler: function (newVal, oldVal) {
// 处理逻辑
},
// 是否深度监听(对于对象或数组,监听其内部属性的变化)
deep: Boolean,
// 是否在初始化时立即执行一次处理函数
immediate: Boolean
}
}
8.2 深度监听(deep)
当我们需要监听一个对象或数组内部属性的变化时,需要设置deep: true。
vue
<div id="app">
<input v-model="user.name">
<input v-model="user.age">
<p>用户信息:{{ user }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
user: {
name: '张三',
age: 20
}
},
watch: {
user: {
handler: function (newVal, oldVal) {
console.log('用户信息发生变化', newVal, oldVal)
},
deep: true // 深度监听,监听user对象内部属性的变化
}
}
})
</script>
在上面的例子中,无论是user.name还是user.age发生变化,watch的处理函数都会被触发。
8.3 立即执行(immediate)
默认情况下,watch的处理函数只会在数据发生变化时执行。如果我们需要在组件初始化时就立即执行一次处理函数,可以设置immediate: true。
vue
watch: {
message: {
handler: function (newVal) {
console.log('消息变为:', newVal)
},
immediate: true // 初始化时立即执行一次
}
}
这样,在组件创建时,即使message的值还没有变化,处理函数也会执行一次,打印出初始的message值。
8.4 监听多个属性
如果需要监听多个属性的变化,并执行同一个处理函数,可以将这些属性的监听配置合并。
vue
watch: {
'user.name': {
handler: function (newVal) {
console.log('用户名变化:', newVal)
},
immediate: true
},
'user.age': {
handler: function (newVal) {
console.log('用户年龄变化:', newVal)
},
immediate: true
}
}
或者,也可以通过一个函数来处理多个属性的变化:
vue
methods: {
handleUserChange: function (newVal, oldVal, propName) {
console.log(`用户${propName}变化:`, newVal)
}
},
watch: {
'user.name': function (newVal, oldVal) {
this.handleUserChange(newVal, oldVal, 'name')
},
'user.age': function (newVal, oldVal) {
this.handleUserChange(newVal, oldVal, 'age')
}
}
九、水果购物车
为了进一步巩固 Vue 的知识,我们来实现一个 “水果购物车” 案例。这个案例将涉及到组件化、状态管理(简单版)、事件通信等知识点,是一个比较综合的实战项目。
9.1 需求分析
展示水果列表,包含水果名称、价格和图片。
可以将水果添加到购物车,选择购买数量。
购物车中可以修改水果数量,也可以删除水果。
实时计算购物车中水果的总价。
9.2 代码实现
我们将项目拆分为两个组件:FruitList(水果列表组件)和ShoppingCart(购物车组件),以及一个父组件App来管理整体数据和状态。
9.2.1 FruitList 组件
vue
<template>
<div class="fruit-list">
<h3>水果列表</h3>
<div class="fruit-item" v-for="fruit in fruits" :key="fruit.id">
<img :src="fruit.image" alt="fruit.image">
<div class="fruit-info">
<h4>{{ fruit.name }}</h4>
<p>价格:{{ fruit.price }}元/斤</p>
<button @click="addToCart(fruit)">加入购物车</button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'FruitList',
props: {
fruits: {
type: Array,
default: () => []
}
},
methods: {
addToCart(fruit) {
this.$emit('add-to-cart', fruit)
}
}
}
</script>
<style scoped>
.fruit-list {
float: left;
width: 60%;
margin-right: 20px;
}
.fruit-item {
display: flex;
margin-bottom: 20px;
border: 1px solid #eee;
padding: 10px;
border-radius: 5px;
}
.fruit-item img {
width: 100px;
height: 100px;
object-fit: cover;
margin-right: 10px;
}
.fruit-info button {
background-color: #42b983;
color: white;
border: none;
padding: 5px 10px;
border-radius: 3px;
cursor: pointer;
}
</style>
9.2.2 ShoppingCart 组件
vue
<template>
<div class="shopping-cart">
<h3>购物车</h3>
<div v-if="cartItems.length === 0">购物车为空</div>
<table v-else border="1" cellpadding="10" cellspacing="0">
<thead>
<tr>
<th>水果名称</th>
<th>单价</th>
<th>数量</th>
<th>小计</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in cartItems" :key="index">
<td>{{ item.name }}</td>
<td>{{ item.price }}</td>
<td>
<button @click="decreaseQuantity(index)" :disabled="item.quantity <= 1">-</button>
{{ item.quantity }}
<button @click="increaseQuantity(index)">+</button>
</td>
<td>{{ item.price * item.quantity }}</td>
<td><button @click="removeItem(index)">删除</button></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3">总计</td>
<td>{{ totalPrice }}</td>
<td></td>
</tr>
</tfoot>
</table>
</div>
</template>
<script>
export default {
name: 'ShoppingCart',
props: {
cartItems: {
type: Array,
default: () => []
}
},
computed: {
totalPrice() {
return this.cartItems.reduce((total, item) => {
return total + item.price * item.quantity
}, 0)
}
},
methods: {
decreaseQuantity(index) {
this.$emit('decrease-quantity', index)
},
increaseQuantity(index) {
this.$emit('increase-quantity', index)
},
removeItem(index) {
this.$emit('remove-item', index)
}
}
}
</script>
<style scoped>
.shopping-cart {
float: left;
width: 35%;
}
table button {
width: 20px;
height: 20px;
padding: 0;
cursor: pointer;
}
</style>
9.2.3 App 父组件
vue
<template>
<div id="app">
<h2>水果购物车</h2>
<fruit-list :fruits="fruits" @add-to-cart="handleAddToCart"></fruit-list>
<shopping-cart
:cartItems="cartItems"
@decrease-quantity="handleDecreaseQuantity"
@increase-quantity="handleIncreaseQuantity"
@remove-item="handleRemoveItem"
></shopping-cart>
</div>
</template>
<script>
import FruitList from './components/FruitList.vue'
import ShoppingCart from './components/ShoppingCart.vue'
export default {
name: 'App',
components: {
FruitList,
ShoppingCart
},
data() {
return {
fruits: [
{ id: 1, name: '苹果', price: 5, image: 'https://images.unsplash.com/photo-1567306301408-9b74779a11af?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fDE2OTg1NTA1ODl8&auto=format&fit=crop&w=1170&q=80' },
{ id: 2, name: '香蕉', price: 3, image: 'https://images.unsplash.com/photo-1571902943202-507ec2618e8f?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fDE2OTg1NTA2MjN8&auto=format&fit=crop&w=1170&q=80' },
{ id: 3, name: '橙子', price: 6, image: 'https://images.unsplash.com/photo-1567306301408-9b74779a11af?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fDE2OTg1NTA1ODl8&auto=format&fit=crop&w=1170&q=80' }
],
cartItems: []
}
},
methods: {
handleAddToCart(fruit) {
const existingItem = this.cartItems.find(item => item.id === fruit.id)
if (existingItem) {
existingItem.quantity++
} else {
this.cartItems.push({
...fruit,
quantity: 1
})
}
},
handleDecreaseQuantity(index) {
this.cartItems[index].quantity--
if (this.cartItems[index].quantity === 0) {
this.cartItems.splice(index, 1)
}
},
handleIncreaseQuantity(index) {
this.cartItems[index].quantity++
},
handleRemoveItem(index) {
this.cartItems.splice(index, 1)
}
}
}
</script>
<style>
#app {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
</style>
9.3 代码解析
组件化:将页面拆分为FruitList和ShoppingCart两个组件,分别负责水果列表的展示和购物车的功能,提高了代码的可维护性和复用性。
数据传递:父组件App通过 props 向子组件传递数据(如fruits和cartItems),子组件通过自定义事件(如@add-to-cart)向父组件传递操作(如添加商品到购物车)。
状态管理:在父组件中管理购物车的状态(cartItems),子组件通过修改父组件的状态来实现购物车的功能。
计算属性:在ShoppingCart组件中使用计算属性totalPrice来实时计算购物车的总价。
通过这个 “水果购物车” 案例,我们可以看到 Vue 在实战中的强大能力,它能够帮助我们快速构建出交互丰富、功能完整的 Web 应用。
总结
本文对 Vue 的核心知识点进行了全面的总结,从指令修饰符、v-bind、v-model到计算属性、watch监视器,再到两个实战案例(成绩管理和水果购物车),涵盖了 Vue 从基础到进阶的主要内容。
学习 Vue,关键在于理解其响应式原理和组件化思想,通过不断的实践来巩固和深化对知识的理解。希望本文能够为大家的 Vue 学习之旅提供有益的参考,帮助大家在前端开发的道路上不断进步。


