文章目录
- vue基础语法补充
- vue的computed
- vue的watch侦听
- 书籍购物车案例
vue基础语法补充
vue的computed
computed
:用于声明要在组件实例上暴露的计算属性。(官方文档描述)
我们已经知道,在模板中可以直接通过插值语法
显示一些data中的数据
。
但是在某些情况,我们可能需要对数据进行一些转化后再显
示,或者需要将多个数据结合起来进行显示
:
- 比如我们需要对多个data数据进行运算、三元运算符来决定结果、数据进行某种转化后显示;
- 在模板中使用表达式,可以非常方便的实现,但是设计它们的初衷是用于
简单的运算
; - 在模板中放入太多的逻辑会
模板过重
和难以维护
;
而且因为多个地方都使用到,所以会有大量重复的代码,那么我们可以将逻辑抽离出去:
- 比如直接逻辑抽取到一个method中,放到methods的options中;
- 但是,这种做法有一个直观的弊端,就是所有的data使用过程都会变成了一个方法的调用,所以正确的做法应该是抽离出来后放入计算属性computed中
用法示例:
<div id="app"><h2>{{fullName}}</h2><!-- 2.显示分数等级 --><h2>{{getScorelevel}}</h2><!-- 3.反转单词显示文本 --><h2>{{reverseMessage}}</h2></div><script>const app = Vue.createApp({data() {return {// 1.姓名firstName: "kobe",lastName: "byrant",// 2.分数及不及格score: 65,// 3.一串文本:对文本中的单词进行反转显示message: "my name is sevgilid"}},methods: {},computed: {// 计算属性对应的是一个函数(经过响应式复杂逻辑转化的都应写在computed里)// 计算属性是有缓存的fullName() {return this.firstName + "" + this.lastName},getScorelevel() {return this.score > 60 ? '及格' : '不及格'},reverseMessage() {return this.message.split("").reverse().join("")}}})app.mount('#app')</script>
vue的watch侦听
watch:
用于声明在数据更改时调用的侦听回调。(官方文档描述)
什么是侦听器呢?
- 开发中我们在data返回的对象中定义了数据,这个数据通过
插值语法等方式绑定到template
中; - 当数据变化时,template会自动进行更新来显示最新的数据;
- 但是在某些情况下,我们希望在
代码逻辑
中监听某个数据的变化,这个时候就需要用侦听器watch
来完成了;
用法:{ [key: string]: string | Function [ Object | Array}
如下示例:
点击按钮后message就会修改,且控制台打印’‘message发生了改变’’
<div id="app"><h2>{{message}}</h2><button @click="changeMessage">修改message</button></div><script>const app = Vue.createApp({data() {return {message: 'hello vue'}},methods: {changeMessage() {this.message = "你好啊,李二狗"}},watch: {message() {console.log("message发生了改变");}}})app.mount('#app')</script>
通过以上例子发现其实就是想监听谁在里面写谁,但这样使用的话只知道数据发生了改变,并不知道改变是什么。
- 其实回调函数里
默认是有传过来两个参
数的:分别是newvalue,oldvalue
,像下面这样修改代码后就可以看到前后数据发生的改变:
watch: {message(newValue,oldValue) {console.log("message已发生改变", newValue, oldValue);}
打印结果:
- 如果是监听的是一个
对象类型
,那么拿到的是代理对象
,可以通过newValue.name这样去拿值
<div id="app"><h2>{{info}}</h2><button @click="changeInfo">改变info</button></div><script>const app = Vue.createApp({data() {return {info:{name:"daa",age:15}}},methods: {changeInfo(){this.info={name:"kkk",age:25}}},watch: {info(newValue,oldValue){console.log("info数据发生了变化", newValue,oldValue);console.log(newValue.name,oldValue.name);![在这里插入图片描述](https://img-blog.csdnimg.cn/9a9764dc762549caa4d9e4905b6336ea.png)}}})app.mount('#app')</script>
控制台打印结果:
- 如果想拿到原生对象:
Vue.toRaw(newValue)
- watch的侦听选项配置:
deep:true
:为true时进行深度监听immediate:true
:为true时第一次渲染直接执行一次监听器
其实默认是不进行深度监听的,像下面的例子:
- 如果
修改的是整个info是可以监听
到的 - 但是只修改
info对象中的一个属性是监听不到
<script>const app = Vue.createApp({data() {return {info: {name:"kkk", age:25}}},methods:{changeInfo(){// 1.修改原对象,可以监听// this.info = {name:"wxx", age:52}// 2.直接修改原对象的一个属性this.info.name = "sevgilid"}},watch:{// 默认watch监听不会进行深度监听(所以只改变属性时未监听到)// info(newValue,oldValue){// console.log("info数据发生了改变", newValue,oldValue);// }// 进行深度监听info:{handler(newValue,oldValue){console.log("info一发生改变",newValue, oldValue);},// 监听器选项://info进行深度监听:加上以下配置后即可监听到属性改变deep:true,// 第一次渲染直接执行一次监听器immediate:true}}})app.mount('#app')</script>
书籍购物车案例
一个相对综合的案例,可以对前面几篇博客知识进行练习(完整代码在文末)
案例说明:
1.在界面上以表格的形式,显示一些书籍的数据;
2.在底部显示书籍的总价格;
3.点击+或者-可以增加或减少书籍数量(如果为1,那么不能继续-);
4.点击移除按钮,可以将书籍移除(当所有的书籍移除完毕时,显示:购物车为空);
5.点击行变色
案例步骤:
1.搭建界面内容:做出表格,调整基本样式
2.获取数据:可以从后台拿数据,这里选择自己在data中模拟数据
3.分析实现逻辑:
- 使用v-for遍历数据配合插值语法实现界面的动态填充
- 为按钮绑定methods中的方法,使用v-if判断为1时不能继续
- 在computed计算属性中实现对价格及数量的逻辑抽取
- 使用split方法移出
- 为点击行动态绑定active样式
步骤代码详解:
遍历数据及加减:
注意事项:
- 遍历时外层使用template包裹
- v-for就要写key(自己写的时候忘记了)
- 因为绑定按钮的时候是动态绑定:所以点击事件的时候要传入参数,即拿到索引才能知道你点击的是哪一个按钮)
- 小于1不可再点击-1按钮时应:disabled={item<=1}
总价响应式:
注意事项:
- 抽取后写入computed计算属性,而非放入methods中进行方法的调用
- 遍历时内部不要忘记加上const
移出操作:
注意事项:
- 绑定事件时传递index参数来判断移出的是第几行
- slice()的使用
行变色:
- 通过点击获取索引index来判断点击的第几行
- 在data中定义currentIndex
- 点击事件中将获取到的index赋值给currentIndex
- tr动态绑定active时使用对象语法,通过判断index === currentIndex的布尔值来动态绑定
案例完整代码:
<!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><script src="../Vue3.js"></script><style>table {border-collapse: collapse;color: brown;text-align: center;}table,th,td {border: 1px solid black;}.active {background-color: aqua;}</style></head><body><div id="app"><div class="shopCurt"><table><thead><tr><th>序号</th><th>商品名字</th><th>价格</th><th>数量</th><th>商品描述</th><th>操作</th></tr></thead><tbody><template v-for="( item,index ) in infos"><tr :class="{active:index === currentIndex}" @click="rowClick(index)"><td>{{ index+1 }}</td><td>{{ item.name }}</td><td>{{ item.price }}</td><td><button @click="decrement(index)" :disabled="item.count<=1">-1</button>{{ item.count }}<button @click="increment(index)">+1</button></td><td>{{ item.dec }}</td><td><button @click="removeBook(index)">{{ item.caozuo }}</button></td></tr></template></tbody></table></div><h2>AllPrice:{{ allPrice }}</h2></div>
</body><script src="./Vue3.js"></script>
<script>const app = Vue.createApp({data() {return {currentIndex: -1,infos: [{ sort: 0, name: "华为电脑", price: 9.9, count: 1, dec: "9.9秒杀快来抢购", caozuo: "移除" },{ sort: 0, name: "iphoneX", price: 12.8, count: 1, dec: "苹果X最新出炉", caozuo: "移除" },{ sort: 0, name: "小米11Plus", price: 13.1, count: 1, dec: "速度来抢", caozuo: "移除" },{ sort: 0, name: "外星人电脑", price: 56, count: 1, dec: "真的便宜", caozuo: "移除" },{ sort: 0, name: "OPPOR11", price: 100, count: 1, dec: "好用不贵", caozuo: "移除" }]}},computed: {allPrice() {let price = 0;for (const item of this.infos) {price += item.price * item.count}return price}},methods: {// 监听加减按钮increment(index) {this.infos[index].count++},decrement(index) {this.infos[index].count--},// 监听行点击变色rowClick(index) {this.currentIndex = index;},// 移出操作removeBook(index) {this.infos.splice(index, 1)}}})app.mount('#app')
</script></html>
实现效果: