🌟 京东秒杀项目训练
目标:实现Tab栏动态渲染与高亮切换
源代码:
<!-- 京东tab栏切换导航高亮 --><!-- 思路1。基于数据,动态渲染tab 2.准备一个下标 记录高亮哪一个tab 3.基于小标动态切换class的类名 -->
<script setup>import { ref } from 'vue'//tab列表const tabs = [{ id:1,name: '蔡徐坤' },{ id:2,name: '陈立农' },{ id:3,name: '范丞丞' }]//当前高亮的下拉,默认是第一个小标为 0const currentIndex = ref(0)</script><template><div><ul><liv-for="(item, index) in tabs":key="item.id"@click="currentIndex = index"><a:class="{active: currentIndex === index }"href="#">{{ item.name }}</a></li></ul></div>
</template><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>
效果展示:
训练步骤
-
数据驱动渲染
-
使用
v-for
动态渲染tabs
数组,生成多个导航标签。 -
核心代码:
<li v-for="(item, index) in tabs" :key="item.id" @click="currentIndex = index"> <a :class="{ active: currentIndex === index }">{{ item.name }}</a> </li>
-
-
动态样式绑定
-
通过
currentIndex
控制当前选中项,使用:class="{ active: 条件 }"
实现高亮效果。 -
知识点:对象语法动态绑定class,键为类名,值为布尔表达式。
-
-
事件处理
-
点击标签时更新
currentIndex
,触发样式变化。 -
核心逻辑:
<li v-for="(item, index) in tabs" :key="item.id" @click="currentIndex = index"> <a :class="{ active: currentIndex === index }">{{ item.name }}</a> </li>
-
知识点提炼
-
v-for指令:动态渲染列表,需绑定
:key
提升性能。 -
动态class:
{ active: currentIndex === index }
,条件满足时添加类名。 -
响应式数据:通过
ref
管理currentIndex
,实现数据驱动视图。
📊 进度条案例训练
目标:通过按钮控制进度条动态变化
源代码:
<!-- 进度条 --><script setup>import { ref } from 'vue'//份数const x = ref(0)
</script><template><div><div class="progress"><divclass="inner":style="{ width: `${(x / 4) * 100}%` }"><span>{{ (x / 4) * 100 }}%</span></div></div><button @click="x = 1">设置25%</button><button @click="x = 2">设置50%</button><button @click="x = 3">设置75%</button><button @click="x = 4">设置100%</button></div>
</template><style>.progress{height: 25px;width: 400px;border-radius: 15px;background-color:#272425;border: 3px solid #272425;box-sizing: border-box;margin-bottom: 30px;}.inner {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:-25px;bottom:-25px;}</style>
效果展示:
训练步骤
-
数据与计算属性
-
定义
x
表示进度份数(0-4),计算属性将x
转换为百分比宽度:<li v-for="(item, index) in tabs" :key="item.id" @click="currentIndex = index"> <a :class="{ active: currentIndex === index }">{{ item.name }}</a> </li>
-
-
动态样式绑定
-
使用
:style
绑定计算属性到进度条内层元素:<div class="inner" :style="widthStyle"></div>
-
-
按钮事件驱动
-
点击按钮更新
x
,触发进度条变化:<button @click="x = 1">25%</button> <button @click="x = 4">100%</button>
-
知识点提炼
-
计算属性:
computed
基于响应式数据生成新值,缓存特性提升性能。 -
动态style:
:style="{ width: 表达式 }"
,支持对象语法绑定行内样式。 -
响应式更新:修改
x.value
后,视图自动同步变化。
📝 成绩管理表单训练
目标:实现成绩增删、统计与本地持久化
源代码:
<!-- 做了一个小表单 -->
<script setup>import { computed, ref } from 'vue'// 商品列表(原始数据) const goodsList = ref([{ id: 1, name: '蔡徐坤', num: 1 },{ id: 2, name: '陈立农', num: 3 },{ id: 3, name: '徐俊大', num: 2 }])// 由于这⾥只有原始数据,没有直接给我们提供商品总数量 // 但是我们可以基于现有的 goodsList 计算得到总数量 // 那么推荐把总数量声明为 计算属性 const totalNum = computed(() => {return goodsList.value.reduce((prev, item) => prev + item.num, 0)})
</script>
<template><h3>礼物清单</h3><table><thead><tr><th>名字</th><th>数量</th></tr></thead><tbody><trv-for="item in goodsList":key="item.id"><td>{{ item.name }}</td><td>{{ item.num }}</td></tr></tbody></table><p>礼物总数:{{ totalNum }} 个</p>
</template>
<style>table {width: 350px;border: 1px solid #333;}table th,table td {border: 1px solid #333;}table td {text-align: center;}
</style>
效果展示:
训练步骤
-
表单双向绑定
-
使用
v-model
绑定表单输入,配合修饰符优化数据:<input v-model.trim="scoreForm.subject" /> <!-- 自动去首尾空格 --> <input v-model.number="scoreForm.score" /> <!-- 自动转数字 -->
-
-
数据增删功能
-
添加:校验数据后推入数组,清空表单:
const onAdd = () => { scoreList.value.push({ ...scoreForm, id: Date.now() }); scoreForm.subject = scoreForm.score = ""; };
-
删除:通过索引移除数据,弹窗确认:
const onAdd = () => { scoreList.value.push({ ...scoreForm, id: Date.now() }); scoreForm.subject = scoreForm.score = ""; };
-
-
统计功能
-
计算总分与平均分:
const totalScore = computed(() => scoreList.value.reduce((sum, item) => sum + item.score, 0) ); const avgScore = computed(() => scoreList.value.length ? totalScore.value / scoreList.value.length : 0 );
-
-
数据持久化
-
使用
watch
深度监听scoreList
,数据变化时存入本地存储:watch( scoreList, (newVal) => localStorage.setItem("SCORE_LIST_KEY", JSON.stringify(newVal)), { deep: true } );
-
知识点提炼
-
v-model修饰符:
.trim
(去空格)、.number
(转数字)。 -
计算属性:处理复杂逻辑(如求和、求平均),依赖变化自动更新。
-
侦听器watch:监听数据变化执行副作用(如存本地),
deep: true
可深度监听对象。 -
数据持久化:利用
localStorage
实现页面刷新不丢失数据。
🎯 总结与节奏感设计
-
京东秒杀:重点练习动态渲染 + 样式绑定,节奏明快,适合熟悉 Vue 指令。
-
进度条:通过计算属性 + 动态样式,直观感受数据驱动视图的魅力。
-
成绩表单:综合运用表单处理 + 计算属性 + 侦听器,完成完整业务逻辑,适合提升实战能力。