Day02
一、今日学习目标
1. 指令补充
- 指令修饰符
- v-bind 对样式增强的操作
- v-model 应用于其他表单元素
2.computed 计算属性
- 基础语法
- 计算属性 vs 方法
- 计算属性的完整写法
- 成绩案例
3.watch 侦听器
- 基础写法
- 完整写法
4. 综合案例(演示)
- 渲染 / 删除 / 修改数量 / 全选 / 反选 / 统计总价 / 持久化
二、指令修饰符
1. 什么是指令修饰符?
所谓指令修饰符就是通过 “.” 指明一些指令 后缀 不同的 后缀 封装了不同的处理操作—> 简化代码
2. 按键修饰符
- @keyup.enter—> 当点击 enter 键的时候才触发
代码演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <div id="app"> <h3>@keyup.enter → 监听键盘回车事件</h3> <input v-model="username" type="text"> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { username: '' }, methods: { } }) </script>
|
3.v-model 修饰符
- v-model.trim—> 去除首位空格
- v-model.number—> 转数字
4. 事件修饰符
- @事件名.stop—> 阻止冒泡
- @事件名.prevent—> 阻止默认行为
- @事件名.stop.prevent—> 可以连用 即阻止事件冒泡也阻止默认行为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| <style> .father { width: 200px; height: 200px; background-color: pink; margin-top: 20px; } .son { width: 100px; height: 100px; background-color: skyblue; } </style>
<div id="app"> <h3>v-model 修饰符 .trim .number</h3> 姓名:<input v-model="username" type="text"><br> 年纪:<input v-model="age" type="text"><br>
<h3>@事件名.stop → 阻止冒泡 </h3> <div @click="fatherFn" class="father"> <div @click="sonFn" class="son"> 儿子 </div> </div>
<h3>@事件名.prevent → 阻止默认行为 </h3> <a @click href="http://www.baidu.com"> 阻止默认行为 </a> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { username: '', age: '', }, methods: { fatherFn () { alert(' 老父亲被点击了 ') }, sonFn (e) { // e.stopPropagation() alert(' 儿子被点击了 ') } } }) </script>
|
三、v-bind 对样式控制的增强 - 操作 Class
为了方便开发者进行样式控制,Vue 扩展了 v-bind 的语法,可以针对 class 类名 和 style 行内样式 进行控制。
1. 语法
1
| <div> :class = " 对象 / 数组 "> 这是一个 div</div>
|
2. 对象语法
当 class 动态绑定的是 对象 时,键就是类名,值就是布尔值,如果值是true,就有这个类,否则没有这个类
1
| <div class="box" :class="{ 类名 1: 布尔值, 类名 2: 布尔值 }"></div>
|
适用场景:一个类名,来回切换
3. 数组语法
当 class 动态绑定的是 数组 时 → 数组中所有的类,都会添加到盒子上,本质就是一个 class 列表
1
| <div class="box" :class="[类名 1, 类名 2, 类名 3]"></div>
|
使用场景: 批量添加或删除类
4. 代码练习
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <style> .box { width: 200px; height: 200px; border: 3px solid #000; font-size: 30px; margin-top: 10px; } .pink { background-color: pink; } .big { width: 300px; height: 300px; } </style>
<div id="app"> <div class="box"> 黑马程序员 </div> <div class="box"> 黑马程序员</div> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <script> const app = new Vue({ el: '#app', data: {
} }) </script>
|
四、京东秒杀 -tab 栏切换导航高亮
1. 需求
当我们点击哪个 tab 页签时,哪个 tab 页签就高亮
2. 准备代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| <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>
<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>
|
3. 思路
1. 基于数据,动态渲染 tab(v-for)
2. 准备一个下标 记录高亮的是哪一个 tab
3. 基于下标动态切换 class 的类名
五、v-bind 对有样式控制的增强 - 操作 Style
1. 语法
1
| <div class="box" :style="{ CSS 属性名 1: CSS 属性值, CSS 属性名 2: CSS 属性值 }"></div>
|
2. 代码练习
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <style> .box { width: 200px; height: 200px; background-color: rgb(187, 150, 156); } </style> <div id="app"> <div class="box"></div> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <script> const app = new Vue({ el: '#app', data: {
} }) </script>
|
3. 进度条案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| <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>
<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>
|
六、v-model 在其他表单元素的使用
1. 讲解内容
常见的表单元素都可以用 v-model 绑定关联 → 快速 获取 或 设置 表单元素的值
它会根据 控件类型 自动选取 正确的方法 来更新元素
1 2 3 4 5 6
| 输入框 input:text ——> value 文本域 textarea ——> value 复选框 input:checkbox ——> checked 单选框 input:radio ——> checked 下拉菜单 select ——> value ...
|
2. 代码准备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| <style> textarea { display: block; width: 240px; height: 100px; margin: 10px 0; } </style> <div id="app"> <h3> 小黑学习网 </h3> 姓名: <input type="text"> <br><br> 是否单身: <input type="checkbox"> <br><br>
性别: <input type="radio"> 男 <input type="radio">女 <br><br>
所在城市: <select> <option> 北京 </option> <option> 上海 </option> <option> 成都 </option> <option> 南京 </option> </select> <br><br> 自我描述: <textarea></textarea> <button> 立即注册</button> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <script> const app = new Vue({ el: '#app', data: {
} }) </script>
|
七、computed 计算属性
1. 概念
基于 现有的数据 ,计算出来的 新属性 。 依赖 的数据变化,自动 重新计算。
2. 语法
- 声明在 computed 配置项 中,一个计算属性对应一个函数
- 使用起来和普通属性一样使用
3. 注意
- computed 配置项和 data 配置项是 同级 的
- computed 中的计算属性 虽然是函数的写法 ,但他 依然是个属性
- computed 中的计算属性 不能 和 data 中的属性 同名
- 使用 computed 中的计算属性和使用 data 中的属性是一样的用法
- computed 中计算属性内部的 this 依然 指向的是 Vue 实例
4. 案例
比如我们可以使用计算属性实现下面这个业务场景
5. 代码准备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| <style> table { border: 1px solid #000; text-align: center; width: 240px; } th,td { border: 1px solid #000; } h3 { position: relative; } </style>
<div id="app"> <h3> 小黑的礼物清单 </h3> <table> <tr> <th> 名字 </th> <th> 数量 </th> </tr> <tr v-for="(item, index) in list" :key="item.id"> <td>{{ item.name }}</td> <td>{{ item.num }} 个</td> </tr> </table>
<p> 礼物总数:? 个</p> </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: ' 篮球 ', num: 1 }, { id: 2, name: ' 玩具 ', num: 2 }, { id: 3, name: ' 铅笔 ', num: 5 }, ] } }) </script>
|
八、computed 计算属性 VS Methods 方法
1.computed 计算属性
作用:封装了一段对于 数据 的处理,求得一个 结果
语法:
- 写在 computed 配置项中
- 作为属性,直接使用
- js 中使用计算属性:this. 计算属性
- 模板中使用计算属性:
2.methods 计算属性
作用:给 Vue 实例提供一个 方法 ,调用以 处理业务逻辑。
语法:
1 2 3 4
| 1. 写在 methods 配置项中 2. 作为方法调用 - js 中调用:this. 方法名() - 模板中调用 {{ 方法名()}} 或者 @事件名 =“方法名”
|
3. 计算属性的优势
缓存特性(提升性能)
计算属性会对计算出来的结果缓存,再次使用直接读取缓存,
依赖项变化了,会自动重新计算 → 并再次缓存
methods 没有缓存特性
通过代码比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| <style> table { border: 1px solid #000; text-align: center; width: 300px; } th,td { border: 1px solid #000; } h3 { position: relative; } span { position: absolute; left: 145px; top: -4px; width: 16px; height: 16px; color: white; font-size: 12px; text-align: center; border-radius: 50%; background-color: #e63f32; } </style>
<div id="app"> <h3>小黑的礼物清单🛒<span>?</span></h3> <table> <tr> <th>名字 </th> <th> 数量 </th> </tr> <tr v-for="(item, index) in list" :key="item.id"> <td>{{ item.name }}</td> <td>{{ item.num }} 个</td> </tr> </table>
<p> 礼物总数:{{ totalCount }} 个</p> </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: ' 篮球 ', num: 3 }, { id: 2, name: ' 玩具 ', num: 2 }, { id: 3, name: ' 铅笔 ', num: 5 }, ] }, computed: { totalCount () { let total = this.list.reduce((sum, item) => sum + item.num, 0) return total } } }) </script>
|
4. 总结
1.computed 有缓存特性 ,methods 没有缓存
2. 当一个结果依赖其他多个值时,推荐使用计算属性
3. 当处理业务逻辑时,推荐使用 methods 方法,比如事件的处理函数
九、计算属性的完整写法
既然计算属性也是属性,能访问,应该也能修改了?
- 计算属性默认的简写,只能读取访问,不能 “ 修改 “
- 如果要 “ 修改 “ → 需要写计算属性的完整写法
完整写法代码演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <div id="app"> 姓:<input type="text" v-model="firstName"> + 名:<input type="text" v-model="lastName"> = <span></span><br><br> <button>改名卡</button> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { firstName: ' 刘 ', lastName: ' 备 ' }, computed: {
}, methods: {
} }) </script>
|
十、综合案例 - 成绩案例
功能描述:
1. 渲染功能
2. 删除功能
3. 添加功能
4. 统计总分,求平均分
思路分析:
1. 渲染功能 v-for :key v-bind: 动态绑定 class 的样式
2. 删除功能 v-on 绑定事件,阻止 a 标签的默认行为
3.v-model 的修饰符 .trim、.number、判断数据是否为空后 再添加、添加后清空文本框的数据
4. 使用计算属性 computed 计算总分和平均分的值
十一、watch 侦听器(监视器)
1. 作用
监视数据变化,执行一些业务逻辑或异步操作
2. 语法
watch 同样声明在跟 data 同级的配置项中
简单写法:简单类型数据直接监视
完整写法:添加额外配置项
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| data: { words: ' 苹果 ', obj: { words: ' 苹果 ' } },
watch: { 数据属性名 (newValue, oldValue) { 一些业务逻辑 或 异步操作。 }, ' 对象. 属性名 ' (newValue, oldValue) { 一些业务逻辑 或 异步操作。 } }
|
3. 侦听器代码准备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
| <style> * { margin: 0; padding: 0; box-sizing: border-box; font-size: 18px; } #app { padding: 10px 20px; } .query { margin: 10px 0; } .box { display: flex; } textarea { width: 300px; height: 160px; font-size: 18px; border: 1px solid #dedede; outline: none; resize: none; padding: 10px; } textarea:hover { border: 1px solid #1589f5; } .transbox { width: 300px; height: 160px; background-color: #f0f0f0; padding: 10px; border: none; } .tip-box { width: 300px; height: 25px; line-height: 25px; display: flex; } .tip-box span { flex: 1; text-align: center; } .query span { font-size: 18px; }
.input-wrap { position: relative; } .input-wrap span { position: absolute; right: 15px; bottom: 15px; font-size: 12px; } .input-wrap i { font-size: 20px; font-style: normal; } </style>
<div id="app"> <div class="query"> <span> 翻译成的语言:</span> <select> <option value="italy">意大利 </option> <option value="english"> 英语 </option> <option value="german"> 德语 </option> </select> </div>
<div class="box"> <div class="input-wrap"> <textarea v-model="words"></textarea> <span><i>⌨️</i> 文档翻译</span> </div> <div class="output-wrap"> <div class="transbox">mela</div> </div> </div> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> const app = new Vue({ el: '#app', data: { words: '' }, }) </script>
|
十二、翻译案例 - 代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| <script> const app = new Vue({ el: '#app', data: { obj: { words: '' }, result: '', }, watch: {
'obj.words' (newValue) { clearTimeout(this.timer) this.timer = setTimeout(async () => { const res = await axios({ url: 'https://applet-base-api-t.itheima.net/api/translate', params: { words: newValue } }) this.result = res.data.data console.log(res.data.data) }, 300) } } }) </script>
|
十三、watch 侦听器
1. 语法
完整写法—> 添加额外的配置项
- deep:true 对复杂类型进行深度监听
- immdiate:true 初始化 立刻执行一次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| data: { obj: { words: ' 苹果 ', lang: 'italy' }, },
watch: { 对象: { deep: true, immdiate:true, handler (newValue) { console.log(newValue) } } }
|
2. 需求
- 当文本框输入的时候 右侧翻译内容要时时变化
- 当下拉框中的语言发生变化的时候 右侧翻译的内容依然要时时变化
- 如果文本框中有默认值的话要立即翻译
3. 代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <script> const app = new Vue({ el: '#app', data: { obj: { words: ' 小黑 ', lang: 'italy' }, result: '', }, watch: { obj: { deep: true, immediate: true, handler (newValue) { clearTimeout(this.timer) this.timer = setTimeout(async () => { const res = await axios({ url: 'https://applet-base-api-t.itheima.net/api/translate', params: newValue }) this.result = res.data.data console.log(res.data.data) }, 300) } } } }) </script>
|
4. 总结
watch 侦听器的写法有几种?
1. 简单写法
1 2 3 4 5 6 7 8
| watch: { 数据属性名 (newValue, oldValue) { 一些业务逻辑 或 异步操作。 }, ' 对象. 属性名 ' (newValue, oldValue) { 一些业务逻辑 或 异步操作。 } }
|
2. 完整写法
1 2 3 4 5 6 7 8 9
| watch: { 数据属性名: { deep: true, immediate: true, handler (newValue) { console.log(newValue) } } }
|
十四、综合案例
购物车案例
需求说明:
- 渲染功能
- 删除功能
- 修改个数
- 全选反选
- 统计 选中的 总价 和 总数量
- 持久化到本地
实现思路:
1. 基本渲染:v-for 遍历、:class 动态绑定样式
2. 删除功能:v-on 绑定事件,获取当前行的 id
3. 修改个数:v-on 绑定事件,获取当前行的 id,进行筛选出对应的项然后增加或减少
4. 全选反选
- 必须所有的小选框都选中,全选按钮才选中 → every
- 如果全选按钮选中,则所有小选框都选中
- 如果全选取消,则所有小选框都取消选中
声明计算属性,判断数组中的每一个 checked 属性的值,看是否需要全部选
5. 统计 选中的 总价 和 总数量:通过计算属性来计算 选中的 总价和总数量
6. 持久化到本地:在数据变化时都要更新下本地存储 watch