一、目标: 数据铺设
-
📝需求1: 把默认数据显示到表格上
-
📝需求2: 注意资产超过100的, 都用红色字体标记出来
1. 💡列表渲染指令(v-for),用来辅助开发者基于一个数组来循环渲染一个列表结构;
-
key:给列表项添加的唯一标识。便于Vue进行列表项的正确排序复用。
2.💡 v-bind对样式控制的增强-操作class;
-
:class="{ 类名1: 布尔值, 类名2: 布尔值 }"。
3. 💡事件修饰符,@事件名.prevent —>阻止默认行为;
-
a标签有默认行为-跳转刷新页面(如果有href属性)。
<tbody v-if="list.length > 0">
<tr v-for="(item,index) in list" :key="item.id">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<!-- 如果价格超过100,就有red这个类 -->
<td :class="{ red:item.price > 100 }">{{ item.price }}</td>
<td>{{ item.time }}</td>
<td><a @click.prevent ="del(item.id)" href="#">删除</a></td>
</tr>
<tr style="background-color: #EEE">
<td>统计:</td>
<td colspan="2">总价为: {{ total }}</td>
<td colspan="2">平均价: {{ average }}</td>
</tr>
</tbody>
二、目标: 数据删除
-
🧾需求3: 点击删除的a标签, 删除数据
-
🧾需求4: 完成总价和均价
1. 🎯事件绑定指令(v-on:
简写为 @)
-
<button v-on:事件名="处理函数(实参)">按钮
-
事件处理函数应该写到一个跟data同级的配置项(methods)中
-
methods中的函数内部的this都指向Vue实例
2. 🎯computed计算属性,封装了一段对于数据的处理,求得一个结果
- 计算属性会对计算出来的结果缓存,再次使用直接读取缓存;依赖项变化了,会自动重新计算 → 并再次缓存。
computed: {
total() {
return this.list.reduce((sum, item) => sum += item.price,0)
},//用于将数组中的每个元素按顺序归约成单个值。它接受两个参数:一个回调函数和一个初始累加器的值。
average() {
if (this.list.length === 0) return 0; // 防止除以0的错误
return this.total / this.list.length;
}
},
methods:{
del(id) {
this.list = this.list.filter(item => item.id !== id)
}// 获取当前行的id,利用filter进行过滤
}
三、目标: 数据新增
-
📣需求5: 实现底部添加资产的功能
-
🪧双向绑定指令(v-model="变量")
-
给表单元素(input、radio、select)使用,双向绑定数据,可以快速 获取 或 设置 表单元素内容
<form class="form-inline">
<div class="form-group">
<label>
资产名称:<input v-model="name" type="text" class="form-control" placeholder="Name" />
</label>
<label>
价格: <input v-model="price" type="text" class="form-control" placeholder="Price" />
</label>
<!-- 注意:一定要阻止表单的默认提交行为,否则刷新网页后数据就会恢复为原来的初始状态 -->
<button class="btn btn-primary" @click.prevent="add">添加资产</button>
</div>
<br>
</form>
add() {
if(this.name.trim().length === 0 || this.price === 0) {
alert("资产名称/价格不能为空") //判断用户输入是否为空给提示
return
}
if(isNaN(Number(this.price))) {
alert("价格必须是数字")
return
}
this.list.push({
id: this.list[this.list.length -1].id + 1,
name: this.name,
price: Number(this.price), // 正确地将字符串转换为数字
time: new Date()
})
this.price = '',
this.name= ''
},
四、目标: 数据监听
-
📚需求6: 侦听list变化, 同步到浏览器本地
1. 🔌持久化到本地: 在数据变化时都要更新下本地存储 watch
-
immdiate:true 初始化 立刻执行一次
- deep:true 对复杂类型进行深度监听
const defaultArr = [
{ id: 100, name: "外套", price: 20, time: new Date('2010-08-12') },
{ id: 101, name: "裤子", price: 30, time: new Date('2013-09-01') },
{ id: 102, name: "鞋", price: 100, time: new Date('2018-11-22') },
{ id: 103, name: "帽子", price: 200, time: new Date('2020-12-12') }
]
const app = new Vue({
el: '#app',
data: {
name: '', // 名称
price: '', // 价格
list: JSON.parse(localStorage.getItem('List')) || defaultArr,
},
watch: {
list: {
deep: true,
handler (newValue) {
// 需要将变化后的 newValue 存入本地 (转JSON)
localStorage.setItem('List', JSON.stringify(newValue))
}
}
}
五、完整代码
<!--初始代码-->
<!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>Document</title>
<link rel="stylesheet" href=" https://cdn.jsdelivr.net/npm/bootstrap@3.7.0-alpha1/dist/css/bootstrap.min.css">
<style>
.red {
color: red;
}
</style>
</head>
<body>
<div id="app">
<div class="container">
<!-- 顶部搜索框模块 -->
<div class="form-group">
<div class="input-group">
<h4>品牌管理</h4>
</div>
</div>
<!-- 数据表格 -->
<table class="table table-bordered table-hover mt-2">
<thead>
<tr>
<th>编号</th>
<th>资产名称</th>
<th>价格</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<!-- 如果价格超过100,就有red这个类 -->
<td class="red"></td>
<td></td>
<td><a href="#">删除</a></td>
</tr>
<tr style="background-color: #EEE">
<td>统计:</td>
<td colspan="2">总价钱为: 100</td>
<td colspan="2">平均价: 100</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5" style="text-align: center">暂无数据</td>
</tr>
</tfoot>
</table>
<!-- 添加资产 -->
<form class="form-inline">
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" placeholder="资产名称" />
</div>
</div>
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" placeholder="价格" />
</div>
</div>
<!-- 阻止表单提交 -->
<button class="btn btn-primary">添加资产</button>
</form>
</div>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
name: "", // 名称
price: 0, // 价格
list: [
{ id: 100, name: "外套", price: 199, time: new Date('2010-08-12') },
{ id: 101, name: "裤子", price: 34, time: new Date('2013-09-01') },
{ id: 102, name: "鞋", price: 25.4, time: new Date('2018-11-22') },
{ id: 103, name: "头发", price: 19900, time: new Date('2020-12-12') }
],
}
})
</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>Document</title>
<link rel="stylesheet" href=" https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css">
<style>
.red {
color: red;
}
#app {
width: 1000px;
margin: 20px auto;
border-radius: 1em;
padding: 1em 2em 2em;
}
</style>
</head>
<body>
<div id="app">
<div class="container">
<!-- 顶部搜索框模块 -->
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<div class="collapse navbar-collapse justify-content-between">
<span class="navbar-brand">品牌管理</span>
<form class="d-flex" role="search">
<input class="form-control me-2" placeholder="Search">
<button class="btn btn-outline-success">Search</button>
</form>
</div>
</div>
</nav>
<!-- 数据表格 -->
<table class="table table-bordered table-hover mt-2">
<thead>
<tr>
<th>编号</th>
<th>资产名称</th>
<th>价格</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody v-if="list.length > 0">
<tr v-for="(item,index) in list" :key="item.id">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<!-- 如果价格超过100,就有red这个类 -->
<td :class="{ red:item.price > 100 }">{{ item.price }}</td>
<td>{{ item.time }}</td>
<td><a @click.prevent ="del(item.id)" href="#">删除</a></td>
</tr>
<tr style="background-color: #EEE">
<td>统计:</td>
<td colspan="2">总价为: {{ total }}</td>
<td colspan="2">平均价: {{ average }}</td>
</tr>
</tbody>
<tfoot v-else>
<tr>
<td colspan="5" style="text-align: center">暂无数据</td>
</tr>
</tfoot>
</table>
<!-- 添加资产 -->
<form class="form-inline">
<div class="form-group">
<label>
资产名称:<input v-model="name" type="text" class="form-control" placeholder="Name" />
</label>
<label>
价格: <input v-model="price" type="text" class="form-control" placeholder="Price" />
</label>
<!-- 注意:一定要阻止表单的默认提交行为,否则刷新网页后数据就会恢复为原来的初始状态 -->
<button class="btn btn-primary" @click.prevent="add">添加资产</button>
</div>
<br>
</form>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const defaultArr = [
{ id: 100, name: "外套", price: 20, time: new Date('2010-08-12') },
{ id: 101, name: "裤子", price: 30, time: new Date('2013-09-01') },
{ id: 102, name: "鞋", price: 100, time: new Date('2018-11-22') },
{ id: 103, name: "帽子", price: 200, time: new Date('2020-12-12') }
]
const app = new Vue({
el: '#app',
data: {
name: '', // 名称
price: '', // 价格
list: JSON.parse(localStorage.getItem('List')) || defaultArr,
},
computed: {
total() {
return this.list.reduce((sum, item) => sum += item.price,0)
},
average() {
if (this.list.length === 0) return 0; // 防止除以0的错误
return this.total / this.list.length;
}
},
methods:{
del(id) {
this.list = this.list.filter(item => item.id !== id)
},
add() {
if(this.name.trim().length === 0 || this.price === 0) {
alert("资产名称/价格不能为空")
return
}
if(isNaN(Number(this.price))) {
alert("价格必须是数字")
return
}
this.list.push({
id: this.list[this.list.length -1].id + 1,
name: this.name,
price: Number(this.price), // 正确地将字符串转换为数字
time: new Date()
})
this.price = '',
this.name= ''
},
},
watch: {
list: {
deep: true,
handler (newValue) {
// 需要将变化后的 newValue 存入本地 (转JSON)
localStorage.setItem('List', JSON.stringify(newValue))
}
}
}
})
</script>
</body>
</html>