阶段练习旨在学习完Vue 指令、计算属性、侦听器-CSDN博客后,进行自我检测,每个练习分为效果显示、需求分析、静态代码、完整代码、总结 四个部分,效果显示和准备代码已给出,我们需要完成“完整代码”部分。
目录
练习1:tab栏的动态高亮显示
效果显示
静态代码
完整代码
错误代码
总结
练习2:进度条
效果显示
静态代码
完整代码
总结
注意
练习3:购物车
效果显示
静态代码
完整代码
分析
部分错误代码
练习1:tab栏的动态高亮显示
效果显示
静态代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>022(1)练习:tab栏的active效果</title><style>* {margin: 0;padding: 0;}ul {display: flex;border-bottom: 2px solid #e01222;padding: 0 10px;}li {width: 100px;height: 50px;line-height: 50px;list-style: none;text-align: center;}li a {display: block;text-decoration: none;font-weight: bold;color: #333333;}li a.active {background-color: #e01222;color: #fff;}</style>
</head>
<body><div id="app"><ul><li><a class="active" href="#">京东秒杀</a></li><li><a href="#">每日特价</a></li><li><a href="#">品类秒杀</a></li></ul></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: '品类秒杀' }]}})</script>
</body>
</html>
完整代码
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>022(1)练习:tab栏的动态高亮显示</title><style>* {margin: 0;padding: 0;}ul {display: flex;border-bottom: 2px solid #e01222;padding: 0 10px;}li {width: 100px;height: 50px;line-height: 50px;list-style: none;text-align: center;}li a {display: block;text-decoration: none;font-weight: bold;color: #333333;}li a.active {background-color: #e01222;color: #fff;}</style>
</head><body><div id="app"><ul><li v-for="(item,index) in list" :key="item.id" @click="activeIndex = index"><a :class="{active : index===activeIndex}" href="#">{{item.name}}</a></li></ul></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {activeIndex: 2,list: [{ id: 1, name: '京东秒杀' },{ id: 2, name: '每日特价' },{ id: 3, name: '品类秒杀' }]}})</script>
</body></html>
错误代码
<li><a :class="{active : activeIndex===item.id}" v-for="(item,index) in list" :key="item.id"@click="activeIndex=id" v-model="activeIndex" href="#">{{item.name}}</a></li>
总结
- 列表渲染
- 点击事件
- v-bind对样式进行控制
练习2:进度条
效果显示
静态代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>022(2)练习:进度条</title><style>.progress {height: 25px;width: 400px;border-radius: 15px;background-color: #272425;border: 3px solid #272425;box-sizing: border-box;margin-bottom: 30px;}.inner {width: 50%;height: 20px;border-radius: 10px;text-align: right;position: relative;background-color: #409eff;background-size: 20px 20px;box-sizing: border-box;transition: all 1s;}.inner span {position: absolute;right: -20px;bottom: -25px;}</style>
</head>
<body><div id="app"><div class="progress"><div class="inner"><span>50%</span></div></div><button>设置25%</button><button>设置50%</button><button>设置75%</button><button>设置100%</button></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {}})</script>
</body>
</html>
完整代码
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>022(2)练习:进度条</title><style>.progress {height: 25px;width: 400px;border-radius: 15px;background-color: #272425;border: 3px solid #272425;box-sizing: border-box;margin-bottom: 30px;}.inner {width: 50%;height: 20px;border-radius: 10px;text-align: right;position: relative;background-color: #409eff;background-size: 20px 20px;box-sizing: border-box;transition: all 1s;}.inner span {position: absolute;right: -20px;bottom: -25px;}</style>
</head><body><div id="app"><div class="progress"><div class="inner" :style="{width: percent+ '%' }"><span>{{percent}}%</span></div></div><button v-for="(item, index) in list" :key="index" @click="percent = item">设置{{item}}%</button></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {percent: 25,list: [25, 50, 75, 100]}})</script>
</body></html>
总结
- 列表渲染
- 点击事件
- v-bind对样式进行控制:操作style
注意
:style="{width: percent+ '%' }"
如果没有将百分比值与单位分开并添加单引号,例如
:style="{width: percent + %}"
,那么Vue.js将会尝试将百分比值与JavaScript表达式中的%
一起解析为字符串,而这不是一个有效的CSS值,会导致样式设置失败。
练习3:购物车
效果显示
静态代码
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><link rel="stylesheet" href="./css/inputnumber.css" /><link rel="stylesheet" href="./css/index.css" /><title>028练习:购物车</title>
</head><body><div class="app-container" id="app"><!-- 顶部banner --><div class="banner-box"><img src="http://autumnfish.cn/static/fruit.jpg" alt="" /></div><!-- 面包屑 --><div class="breadcrumb"><span>🏠</span>/<span>购物车</span></div><!-- 购物车主体 --><div class="main"><div class="table"><!-- 头部 --><div class="thead"><div class="tr"><div class="th">选中</div><div class="th th-pic">图片</div><div class="th">单价</div><div class="th num-th">个数</div><div class="th">小计</div><div class="th">操作</div></div></div><!-- 身体 --><div class="tbody"><div class="tr active"><div class="td"><input type="checkbox" checked /></div><div class="td"><img src="http://autumnfish.cn/static/火龙果.png" alt="" /></div><div class="td">6</div><div class="td"><div class="my-input-number"><button class="decrease"> - </button><span class="my-input__inner">2</span><button class="increase"> + </button></div></div><div class="td">12</div><div class="td"><button>删除</button></div></div><div class="tr"><div class="td"><input type="checkbox" /></div><div class="td"><img src="http://autumnfish.cn/static/荔枝.png" alt="" /></div><div class="td">7</div><div class="td"><div class="my-input-number"><button disabled class="decrease"> - </button><span class="my-input__inner">1</span><button class="increase"> + </button></div></div><div class="td">14</div><div class="td"><button>删除</button></div></div></div></div><!-- 底部 --><div class="bottom"><!-- 全选 --><label class="check-all"><input type="checkbox" />全选</label><div class="right-box"><!-- 所有商品总价 --><span class="price-box">总价 : ¥ <span class="price">24</span></span><!-- 结算按钮 --><button class="pay">结算( 6 )</button></div></div></div><!-- 空车 --><div class="empty">🛒空空如也</div></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {// 水果列表fruitList: [{id: 1,icon: 'http://autumnfish.cn/static/火龙果.png',isChecked: true,num: 2,price: 6,},{id: 2,icon: 'http://autumnfish.cn/static/荔枝.png',isChecked: false,num: 7,price: 20,},{id: 3,icon: 'http://autumnfish.cn/static/榴莲.png',isChecked: false,num: 3,price: 40,},{id: 4,icon: 'http://autumnfish.cn/static/鸭梨.png',isChecked: true,num: 10,price: 3,},{id: 5,icon: 'http://autumnfish.cn/static/樱桃.png',isChecked: false,num: 20,price: 34,},],},})</script>
</body></html>
完整代码
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><link rel="stylesheet" href="028inputnumber.css" /><link rel="stylesheet" href="028index.css" /><title>028练习:购物车</title>
</head><body><div class="app-container" id="app"><!-- 顶部banner --><div class="banner-box"><img src="#" alt="" /></div><!-- 面包屑 --><div class="breadcrumb"><span>🏠</span>/<span>购物车</span></div><!-- 购物车主体 --><div class="main"><div class="table"><!-- 头部 --><div class="thead"><div class="tr"><div class="th">选中</div><div class="th th-pic">图片</div><div class="th">单价</div><div class="th num-th">个数</div><div class="th">小计</div><div class="th">操作</div></div></div><!-- 身体 --><div class="tbody"><div class="tr" :class="{active: item.isChecked==true }" v-for="(item, index) in fruitList" :key="item.id"><div class="td"><input type="checkbox" @click="check(index)" v-model="item.isChecked" /></div><div class="td"><img src="#" alt="" /></div><div class="td">{{item.price}}</div><div class="td"><div class="my-input-number"><button class="decrease" @click="item.num--"> - </button><span class="my-input__inner">{{item.num}}</span><button class="increase" @click="item.num++"> + </button></div></div><div class="td">{{subTotalCount(index)}}</div><div class="td"><button @click="del(item.id)">删除</button></div></div></div></div><!-- 底部 --><div class="bottom"><!-- 全选 --><label class="check-all"><input type="checkbox" @click="toggleAllCheckbox" v-model="allClickFlag" />全选</label><div class="right-box"><!-- 所有商品总价 --><span class="price-box">总价 : ¥ <span class="price">{{totalCount}}</span></span><!-- 结算按钮 --><button class="pay">结算( {{totalKind}} )</button></div></div></div><!-- 空车 --><div class="empty" v-show="num1===0">🛒空空如也</div></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {num1: 0,allClickFlag: false,// 水果列表fruitList: [{id: 1,icon: '#',isChecked: false,num: 2,price: 6,},{id: 2,icon: '#',isChecked: false,num: 7,price: 20,},{id: 3,icon: '#',isChecked: false,num: 3,price: 40,},{id: 4,icon: '#',isChecked: false,num: 10,price: 3,},{id: 5,icon: '#',isChecked: false,num: 20,price: 34,},],},methods: {subTotalCount(index) {return this.fruitList[index].num * this.fruitList[index].price},del(id) {this.fruitList = this.fruitList.filter(item => item.id != id)},check(index) {this.fruitList[index].isChecked = !this.fruitList[index].isChecked;if (this.fruitList[index].isChecked == true) this.num1++;else this.num1--;if (this.fruitList.every(item => {return item.isChecked === !this.allClickFlag;})) {this.allClickFlag = !this.allClickFlag;} else {const foundItem = this.fruitList.find(item => {return this.allClickFlag === true;});if (foundItem) {this.allClickFlag = !this.allClickFlag;}}},allClick() {const isChecked = this.allClickFlag;this.fruitList.forEach(item => {item.isChecked = isChecked;});},toggleAllCheckbox() {this.allClickFlag = !this.allClickFlag}},computed: {totalCount() {let total = this.fruitList.reduce((sum, item) => {if (item.isChecked === true) {return sum + item.num * item.price;} else {return sum;}}, 0);return total;},totalKind() {let kind = this.fruitList.reduce((sum, item) => {if (item.isChecked === true) {return sum + item.num;} else {return sum;}}, 0);return kind;}},watch: {'allClickFlag': {immediate: true,handler(newVal) {if (newVal === true) {this.fruitList.forEach(item => {item.isChecked = true;this.num1++;});} else {this.fruitList.forEach(item => {item.isChecked = false;this.num1--;});}}}},'num1': {immediate: true,handler(newVal) {if (newVal === this.fruitList.length) this.allClickFlag = true;else this.allClickFlag = false;}}})</script>
</body></html>
分析
部分错误代码
错误原因:toggleAllCheckbox 方法会切换 allClickFlag 的值,从而控制全选按钮的选中状态。但是,当用户手动取消某个待选框的选中状态时,并没有调用 toggleAllCheckbox 方法来更新 allClickFlag 的值。因此,全选按钮的状态不会根据待选框的实际状态自动更新。