◆ 指令补充
指令修饰符
通过 "." 指明一些指令 后缀,不同 后缀 封装了不同的处理操作 → 简化代码
v-bind 对于样式控制的增强
为了方便开发者进行样式控制, Vue 扩展了 v-bind 的语法,可以针对 class 类名 和 style 行内样式 进行控制 。
v-bind 对于样式控制的增强 - 操作class
语法 :class = "对象/数组"
v-bind 对于样式控制的增强 - 操作style
语法 :style = "样式对象"
v-model 应用于其他表单元素
常见的表单元素都可以用 v-model 绑定关联 → 快速 获取 或 设置 表单元素的值
它会根据 控件类型 自动选取 正确的方法 来更新元素
简单来说就是使用v-model来给表单元素设置默认的初始值
<!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><style>textarea {display: block;width: 240px;height: 100px;margin: 10px 0;}</style>
</head>
<body><div id="app"><h3>小黑学习网</h3>姓名:<input type="text" v-model="username"> <br><br>是否单身:<input type="checkbox" v-model="isSingle"> <br><br><!-- 前置理解:1. name: 给单选框加上 name 属性 可以分组 → 同一组互相会互斥2. value: 给单选框加上 value 属性,用于提交给后台的数据结合 Vue 使用 → v-model-->性别: <input v-model="sex" type="radio" name="sex" value="0">男<input v-model="sex"type="radio" name="sex" value="1">女<br><br><!-- 前置理解:1. option 需要设置 value 值,提交给后台2. select 的 value 值,关联了选中的 option 的 value 值结合 Vue 使用 → v-model-->所在城市:<select v-model="cityId"><option value="100">北京</option><option value="101">上海</option><option value="102">成都</option><option value="103">南京</option></select><br><br>自我描述:<textarea v-model="description"></textarea> <button>立即注册</button></div><script src="./vue.js"></script><script>const app = new Vue({el: '#app',data: {username: '',isSingle: true,sex: '1',cityId: '102',description: ''}})</script>
</body>
</html>
◆ computed 计算属性
概念:基于现有的数据,计算出来的新属性。 依赖的数据变化,自动重新计算。
语法:
① 声明在 computed 配置项中,一个计算属性对应一个函数
② 使用起来和普通属性一样使用 {{ 计算属性名 }}
计算属性 → 可以将一段 求值的代码 进行封装
computed 计算属性 vs methods 方法
计算属性完整写法 (重点)
成绩案例
<!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="./styles/index.css" /><title>Document</title></head><body><div id="app" class="score-case"><div class="table"><table><thead><tr><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>{{index+1}}</td><td>{{item.subject}}</td><td :class="{red: item.score<60}">{{item.score}}</td><td><a @click.prevent="del(item.id)" href="#">删除</a></td></tr></tbody><tbody v-else><tr><td colspan="5"><span class="none">暂无数据</span></td></tr></tbody><tfoot><tr><td colspan="5"><span>总分:{{total}}</span><span style="margin-left: 50px">平均分:{{avg}}</span></td></tr></tfoot></table></div><div class="form"><div class="form-item"><div class="label">科目:</div><div class="input"><inputtype="text"placeholder="请输入科目"v-model.trim="subject"/></div></div><div class="form-item"><div class="label">分数:</div><div class="input"><inputtype="text"placeholder="请输入分数"v-model.number="score"/></div></div><div class="form-item"><div class="label"></div><div class="input"><button class="submit" @click="add()">添加</button></div></div></div></div><script src="../vue.js"></script><script>const app = new Vue({el: '#app',data: {list: [{ id: 1, subject: '语文', score: 20 },{ id: 7, subject: '数学', score: 99 },{ id: 12, subject: '英语', score: 70 },],subject: '',score: ''},computed: {total(){// 使用数组求和函数return this.list.reduce((sum,item)=>sum+item.score,0)},avg(){if(this.list.length === 0){return 0}return (this.list.reduce((sum,item)=>sum+item.score,0)/this.list.length).toFixed(2)}},methods: {del(id){this.list = this.list.filter(item=>id!==item.id)},add(){if(!this.subject){alert('请输入科目名称!')return}console.log( typeof this.score );if( typeof this.score !=='number' || !(this.score >= 0 && this.score <=100)){alert('你输入的不是数字,或者分数不在0-100之间!')return}this.list.unshift({ id: +new Date(), subject: this.subject, score: this.score })}}})</script></body>
</html>
◆ watch 侦听器(重点)
作用:监视数据变化,执行一些 业务逻辑 或 异步操作。
语法:
① 简单写法 → 简单类型数据,直接监视
② 完整写法 → 添加额外配置项
简单写法
完整写法
小结:
watch侦听器的语法有几种?
① 简单写法 → 监视简单类型的变化
② 完整写法 → 添加额外的配置项 (深度监视复杂类型,立刻执行)
◆ 综合案例:水果购物车
<!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>购物车</title></head><body><div class="app-container" id="app"><!-- 顶部banner --><div class="banner-box"><img src="./img/fruit.jpg" alt="" /></div><!-- 面包屑 --><div class="breadcrumb"><span>🏠</span>/<span>购物车</span></div><!-- 购物车主体 --><div class="main" v-if="fruitList.length>0"><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" v-for="(item,index) in fruitList" :key="" :class="{active: item.isChecked}"><div class="td"><input type="checkbox" v-model="item.isChecked"/></div><div class="td"><img :src="item.icon" alt="" /></div><div class="td">{{item.price}}</div><div class="td"><div class="my-input-number"><button class="decrease" @click="reduce(item.id)"> - </button><span class="my-input__inner">{{item.num}}</span><button class="increase" @click="item.num++"> + </button></div></div><div class="td">{{(item.price*item.num).toFixed()}}</div><div class="td"><button @click="del(item.id)"> 删除</button></div></div></div></div><!-- 底部 --><div class="bottom"><!-- 全选 --><label class="check-all"><input type="checkbox" v-model="isAll"/>全选</label><div class="right-box"><!-- 所有商品总价 --><span class="price-box">总价 : ¥ <span class="price">{{totalMoney}}</span></span><!-- 结算按钮 --><button class="pay">结算( {{totalNum}} )</button></div></div></div><!-- 空车 --><div class="empty" v-else>🛒空空如也</div></div><script src="../vue.js"></script><script>let defaultALL = [{id: 1,icon: './img/火龙果.png',isChecked: true,num: 2,price: 6,},{id: 2,icon: './img/荔枝.png',isChecked: false,num: 7,price: 20,},{id: 3,icon: './img/榴莲.png',isChecked: false,num: 3,price: 40,},{id: 4,icon: './img/鸭梨.png',isChecked: true,num: 10,price: 3,},{id: 5,icon: './img/樱桃.png',isChecked: false,num: 20,price: 34,}]const app = new Vue({el: '#app',data: {// 水果列表//JSON.parse(localStorage.getItem('fruitList'))||[]fruitList: JSON.parse(localStorage.getItem('fruitList'))||[]},computed: {// 完整写法isAll:{get(value){return this.fruitList.every(item=>item.isChecked)},set(value){this.fruitList.forEach(item=>item.isChecked =value)}},totalMoney(){return this.fruitList.reduce((sum,item)=>{if(item.isChecked){return sum+(item.num*item.price)}else{return sum}},0)},totalNum(){return this.fruitList.reduce((sum,item)=>{if(item.isChecked){return sum + item.num}else{return sum}},0)}},methods: {del(id){this.fruitList = this.fruitList.filter((item)=>id!==item.id)},reduce(id){//得到数组对应的数据let obj = this.fruitList.find(item=>item.id===id)if(obj.num>1){obj.num--}// console.log(index);// console.log(this.fruitList[index]);// console.log(num);}},// 6 持久化到本地//监听数组数据变化watch:{//使用完整写法fruitList:{deep: true,handler (newValue){//将变化的值存储到本地localStorage.setItem('fruitList',JSON.stringify(newValue))}}}})</script></body>
</html>
小结:
业务技术点总结:
1. 渲染功能: v-if/v-else v-for :class
2. 删除功能: 点击传参 filter过滤覆盖原数组
3. 修改个数:点击传参 find找对象
4. 全选反选:计算属性computed 完整写法 get/set
5. 统计选中的总价和总数量: 计算属性computed reduce条件求和
6. 持久化到本地: watch监视,localStorage,JSON.stringify, JSON.parse