概述
文章目录
-
- 计算属性computed
-
- 1.认识计算属性
- 2.案例实现
-
- 实现思路一:模板语法
- 实现思路二:method
- 实现思路三:computed
- 3.计算属性 VS methods
- 4.计算属性的set和get
- 监听器watch
-
- 1.认识监听器watch
- 2.watch的配置选项
- 3.watch的其他方式(了解)
- 综合案例
计算属性computed
1.认识计算属性
我们知道,在模板中可以直接通过插值语法显示一些data中的数据。
但是在某些情况,我们可能需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示;
-
比如我们需要对多个data数据进行运算、三元运算符来决定结果、数据进行某种转化后显示;
-
在模板中使用表达式,可以非常方便的实现,但是设计它们的初衷是用于简单的运算;
-
在模板中放入太多的逻辑会让模板过重和难以维护;
-
并且如果多个地方都使用到,那么会有大量重复的代码;
我们有没有什么方法可以将逻辑抽离出去呢?
-
可以,其中一种方式就是将逻辑抽取到一个method中,放到methods的options中;
-
但是,这种做法有一个直观的弊端,就是所有的data使用过程都会变成了一个方法的调用;
-
另外一种方式就是使用计算属性computed;
那么什么是计算属性呢?
-
官方并没有给出直接的概念解释;
-
而是说:对于任何包含响应式数据的复杂逻辑,你都应该使用计算属性;
-
计算属性将被混入到组件实例中 , 所有 getter 和 setter 的 this 上下文自动地绑定为组件实例;
计算属性的用法:
-
选项:computed
-
类型:
{ [key: string]: Function | { get: Function, set: Function } }
那接下来我们通过案例来理解一下这个计算属性。
2.案例实现
我们来看三个案例:
案例一:我们有两个变量:firstName和lastName,希望它们拼接之后在界面上显示;
案例二:我们有一个分数:score
-
当score大于60的时候,在界面上显示及格;
-
score小于60的时候,在界面上显示不及格;
案例三:我们有一个变量message,记录一段文字:比如Hello World
-
某些情况下我们是直接显示这段文字;
-
某些情况下我们需要对这段文字进行反转;
我们可以有三种实现思路:
思路一:在模板语法中直接使用表达式;
思路二:使用method对逻辑进行抽取;
思路三:使用计算属性computed;
实现思路一:模板语法
思路一的实现:模板语法
-
缺点一:模板中存在大量的复杂逻辑,不便于维护(模板中表达式的初衷是用于简单的计算);
-
缺点二:当有多次一样的逻辑时,存在重复的代码;
-
缺点三:多次使用的时候,很多运算也需要多次执行,没有缓存;
{{ firstNmae}} {{ lastName }}
{{ score >= 60? "及格": "不及格" }}
{{ message.split(" ").reverse().join(" ") }}
实现思路二:method
思路二的实现:method实现
-
缺点一:我们事实上想显示的是一个结果,但是结果都变成了一种方法的调用;
-
缺点二:多次使用方法的时候,没有缓存,也需要多次计算;
{{ getFullName() }}
{{ getScoreLevel() }}
{{ reverseMessage() }}
实现思路三:computed
思路三的实现:computed实现
-
注意:计算属性看起来像是一个函数,但是我们在使用的时候不需要加(),这个后面讲setter和getter时会讲到;
-
我们会发现无论是直观上,还是效果上计算属性都是更好的选择;
-
并且计算属性是有缓存的;
{{ fullName }}
{{ scoreLevel }}
{{ reverseMessage }}
3.计算属性 VS methods
在上面的实现思路中,我们会发现计算属性和methods的实现看起来是差别是不大的,而且我们多次提到计算属性有缓存的。
-
接下来我们来看一下同一个计算多次使用,计算属性和methods的差异:
const app = Vue.createApp({
data() {
return {
firstNmae: “chen”,
lastName: “yq”,
};
},
// 1.定义methods方法
methods: {
getFullName() {
console.log(“调用了methods的getFullName”);
return this.firstNmae + " " + this.lastName;
},
},// 2.定义计算属性
computed: {
fullName() {
console.log(“调用了computed的fullName”);
return this.firstNmae + " " + this.lastName;
},
},
});{{ getFullName() }}
{{ getFullName() }}
{{ getFullName() }}
{{ getFullName() }}
{{ fullName }}
{{ fullName }}
{{ fullName }}
{{ fullName }}
打印的结果如下 ( 我们会发现methods调用了四次, 而computed只会调用一次 ):
这是什么原因呢?
-
这是因为计算属性会基于它们的依赖关系进行缓存;
-
在数据不发生变化时,计算属性是不需要重新计算的;
-
但是如果依赖的数据发生变化,在使用时,计算属性依然会重新进行计算;
例如我们对上面代码在添加一个按钮, 要求点击按钮, 内容发生改变
<!-- 1.使用methods -->
<h2>{{ getFullName() }}</h2>
<h2>{{ getFullName() }}</h2>
<h2>{{ getFullName() }}</h2>
<h2>{{ getFullName() }}</h2>
<!-- 2.使用computed -->
<h2>{{ fullName }}</h2>
<h2>{{ fullName }}</h2>
<h2>{{ fullName }}</h2>
<h2>{{ fullName }}</h2>
<!-- 3.添加按钮点击改变信息 -->
<button @click="changeMessage">改变信息</button>
那么我们来看看点击按钮前后的打印效果:
- 点击按钮改变前:
- 点击按钮改变信息后:
- 改变信息后计算属性会重新执行一次, 而methods又重新执行了四次
- 由此可见, computed的性能是更高的
4.计算属性的set和get
其实上面的代码中, 我们使用的都是计算属性的简写方式
- 计算属性有完整的写法, 只不过开发中很少会这样写
- 下面给大家介绍一下计算属性的完整写法
完整写法中, 我们设置一个计算属性, 这个计算属性其实是一个对象
- 对象中有两个方法, 一个是set, 一个是get
计算属性在大多数情况下,只需要一个getter方法即可,所以我们会将计算属性直接写成一个函数。
-
计算属性的完整写法
computed: {
fullName: {
get() {
return this.firstName + " " + this.lastName;
},
},
} -
当我们只需要getter方法的时候, 我们可以直接写出一个函数, 也就是我们之前的写法
computed: {
fullName() {
return this.firstName + " " + this.lastName;
},
}
但是,如果我们确实想设置或修改计算属性的值(了解), 基本不会使用set
-
这个时候我们也可以给计算属性设置一个setter的方法;
{{ fullName }}
监听器watch
1.认识监听器watch
什么是侦听器呢?
-
开发中我们在data返回的对象中定义了数据,这个数据通过插值语法等方式绑定到template中;
-
当数据变化时,template会自动进行更新来显示最新的数据;
-
但是在某些情况下,我们希望在代码逻辑中监听某个数据的变化,这个时候就需要用侦听器watch来完成了;
侦听器的用法如下:
-
选项:watch
-
类型:
{[key: string]: string | Function | Object | Array}
演示代码, 例如监听message发生了改变
// watch监听器
watch: {
// 监听message的改变
message() {
console.log("message发生了改变");
},
}
-
如果我们想要拿到message改变之前的信息呢
-
其实默认是有两个参数的, 一个oldValue改变之前的数据, 一个是newValue改变之后的数据
watch: {
// 默认有两个参数
message(newValue, oldValue) {
console.log(“message改变前是:”, oldValue);
console.log(“message改变后是:”, newValue);
},
} -
如果是对象类型, 参数获取到的是Proxy代理对象
// 监听info对象
info(newValue, oldValue) {
// 如果是对象类型, 那么拿到的是代理对象
console.log(“info数据发生了变化:”, newValue, oldValue);
// 代理对象同样可以使用对象的属性
console.log(newValue.name, oldValue.name);
}, -
我们也可以获取Proxy代理对象的原始对象
// 监听info对象
info(newValue, oldValue) {
// 通过toRaw方法获取原始对象
console.log(Vue.toRaw(newValue), Vue.toRaw(oldValue));
},
2.watch的配置选项
我们先来看一个例子:
-
当我们点击按钮的时候会修改info.name的值;
-
这个时候我们使用watch来侦听info,可以侦听到info.name的变化吗?答案是不可以。
{{ info.name }}
这是因为默认情况下,watch只是在侦听info的引用变化,对于内部属性的变化是不会做出响应的:
-
这个时候我们可以使用一个选项deep进行更深层的侦听;
-
注意前面我们说过watch里面侦听的属性对应的也可以是一个Object;
watch: {
// 进行更深层次的监听
info: {
// 回调函数放在handler中
handler(newValue, oldValue) {
console.log(“info内部数据发生了变化”);
},
// 添加deep选项, 开启深度监听
deep: true,
},
},
还有另外一个属性,是希望一开始的就会立即执行一次:
-
这个时候我们使用immediate选项;
-
这个时候无论后面数据是否有变化,侦听的函数都会有限执行一次;
watch: {
// 进行更深层次的监听
info: {
// 回调函数放在handler中
handler(newValue, oldValue) {
console.log(“info内部数据发生了变化”);
},
// 添加deep选项, 开启深度监听
deep: true,
// 添加immediate选项, 启动默认监听
immediate: true,
},
},
3.watch的其他方式(了解)
另外一个是Vue3文档中没有提到的,但是Vue2文档中有提到的是侦听对象的属性:
-
例如刚刚监听info.name属性, 可以有如下写法:
watch: {
“info.name”: function (newValue, oldValue) {
console.log(“info.name发生了改变”, newValue, oldValue);
},
},
还有另外一种方式就是使用 w a t c h 的 A P I :我们可以在 c r e a t e d 的生命周期(暂时了解 , 后续会讲到)中,使用 t h i s . watch 的API:我们可以在created的生命周期(暂时了解, 后续会讲到)中,使用 this. watch的API:我们可以在created的生命周期(暂时了解,后续会讲到)中,使用this.watchs 来侦听;
-
第一个参数是要侦听的源;
-
第二个参数是侦听的回调函数callback;
-
第三个参数是额外的其他选项,比如deep、immediate;
created() {
this.$watch(“info”, (newValue, oldValue) => {
console.log(“info内部数据发生了变化”);
}, { deep: true, immediate: true})
}
综合案例
我们已经学习了很多Vue的语法, 现在我们来做一个相对综合一点的练习:书籍购物车
案例需求:
- 在界面上以表格的形式,显示一些书籍的数据;
- 点击+或者-可以增加或减少书籍数量(如果为1,那么不能继续-);
- 点击移除按钮,可以将书籍移除(当所有的书籍移除完毕时,显示:您当前没有选择任何商品~~~);
- 在底部显示书籍的总价格;
- 点击某一行时, 某一行高亮
思路分析:
- 购买数量不能为负数, 等于零的的时候将按钮禁用:
:disabled="item.count === 0"
- 购买数量的增加和减少, 在v-for里面需要确定点击的是哪一个书籍的增加/减少, 需要在点击事件里面去传递一个index作为参数, 用于确定增加目标
- 移除同理: 需要确定具体的移除目标, 点击事件里传入index, 使用数组的方法
splice(index, 1)
进行移除 - 总价: 使用计算属性计算总价格, 遍历数组拿到每一个对象, 让数量*价格, 最后然后总价格
- 购物车为空时, 显式一行字, 用v-if 和 v-else, 判断books.lenght是否等于0
- 点击某一处高亮, 把样式写在一个类中(例如active), 动态添加类
:class = "{active: index === currentIndex}"
示例源代码:
-
css源代码
-
html和js代码
书籍名称 出版日期 价格 购买数量 操作
先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦
最后
以上就是潇洒裙子为你收集整理的Vue基础-Options API(computed和watch)-Vue基础综合练习 书籍购物车案例的全部内容,希望文章能够帮你解决Vue基础-Options API(computed和watch)-Vue基础综合练习 书籍购物车案例所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复