计算属性computed
什么是计算属性呢?
官方并没有给出直接的概念解释;
而是说:对于任何包含响应式数据的复杂逻辑,你都应该使用计算属性;
计算属性将被混入到组件实例中。所有 getter 和 setter 的 this 上下文自动地绑定为组件实例;
我们可以有三种实现思路:
- 思路一:在模板语法中直接使用表达式;
过于复杂的逻辑判断
重复多次的使用,没有缓存
- 思路二:使用method对逻辑进行抽取;
我们事实上先显示的是一个结果,但是都变成了一种方法的调用;
多次使用方法的时候,没有缓存,也需要多次计算;
- 思路三:使用计算属性computed;
<template id="my-app">
<h2>{{ fullName }}</h2>
</template>
<script src="../js/vue.js"></script>
<script>
const App = {
template: '#my-app',
data() {
return {
firstName: "Kobe",
lastName: "Bryant",
}
},
computed: {
fullName() {
return this.firstName + this.lastName;
},
}
Vue.createApp(App).mount('#app');
</script>
conputed与method的差异
<div id="app"></div>
<template id="my-app">
<!-- 1.使用methods -->
<h2>{{getResult()}}</h2>
<h2>{{getResult()}}</h2>
<h2>{{getResult()}}</h2>
<!-- 2.使用computed -->
<h2>{{result}}</h2>
<h2>{{result}}</h2>
<h2>{{result}}</h2>
</template>
<script src="../js/vue.js"></script>
<script>
const App = {
template: '#my-app',
data() {
return {
score: 90
}
},
computed: {
result() {
console.log("调用了计算属性result的getter");
return this.score >= 60 ? "及格": "不及格";
}
},
methods: {
getResult() {
console.log("调用了getResult方法");
return this.score >= 60 ? "及格": "不及格";
}
}
}
Vue.createApp(App).mount('#app');
</script>
computed值使用了一次,之后都是使用的缓存
- 这是因为计算属性会基于它们的依赖关系进行缓存;
- 在数据不发生变化时,计算属性是不需要重新计算的;
- 但是如果依赖的数据发生变化,在使用时,计算属性依然会重新进行计算;
method每次的使用都重新调用的方法,重复执行
computed属性的setter和getter
计算属性在大多数情况下,只需要一个getter方法即可,所以我们会将计算属性直接写成一个函数。
{ [key: string]: Function | { get: Function, set: Function } }
<template id="my-app">
<h2>{{fullName}}</h2>
<button @click="setNewName">设置新名字</button>
</template>
<script src="../js/vue.js"></script>
<script>
const App = {
template: '#my-app',
data() {
return {
firstName: "Kobe",
lastName: "Bryant"
}
},
computed: {
fullName: {
get() {
return this.firstName + " " + this.lastName;
},
set(value) {
const names = value.split(" ");
this.firstName = names[0];
this.lastName = names[1];
}
}
},
methods: {
setNewName() {
this.fullName = "coder why";
}
}
}
Vue.createApp(App).mount('#app');
</script>
侦听器watch
类型:{ [key: string]: string | Function | Object | Array}
什么是侦听器呢?
- 开发中我们在data返回的对象中定义了数据,这个数据通过插值语法等方式绑定到template中;
- 当数据变化时,template会自动进行更新来显示最新的数据;
- 但是在某些情况下,我们希望在代码逻辑中监听某个数据的变化,这个时候就需要用侦听器watch来完成了;
将question值绑定了watch侦听,从而question的每次变换都会进行相应的逻辑处理
与v-model双向绑定的区别:
v-model只是监听了data的变化,例如键盘在input的输入时,绑定的相应data随之变化
watch监听data,并且在data改变时进行相应的逻辑处理:
例如示例代码中 this.getAnwser(newValue); 每次data改变的时候调用getAnswer方法
(例如在input中输入asdb,键盘输入了四个字符,data改变了4次,随之getAnswer方法也被调用了四次)
<div id="app"></div>
<template id="my-app">
<label for="question">
请输入问题:
<input type="text" id="question" v-model="question">
</label>
</template>
<script src="../js/vue.js"></script>
<script>
const App = {
template: '#my-app',
data() {
return {
question: "",
info: {
name: "why"
}
}
},
watch: {
question(newValue, oldValue) {
this.getAnwser(newValue);
}
},
methods: {
getAnwser(question) {
console.log(`${question}的问题答案是哈哈哈哈`);
}
}
}
Vue.createApp(App).mount('#app');
</script>
${ }是es6的拼接字符串写法
侦听器watch的配置选项
我们先来看一个例子:
当点击修改info1时:
- 这个时候我们使用watch来侦听info,可以侦听到吗?答案是不可以。
- 此时改变的是info内部的属性:
info: {
name: "kobe",
age:"19"
}
当点击修改info2时:
- 这个时候我们使用watch来侦听info,可以侦听到吗?答案是可以。
- 此时改变的是info属性:
info: {
name: "jack",
}
因为默认情况下,watch只是在侦听info的引用变化,对于内部属性的变化是不会做出相应的
<div id="app"></div>
<template id="my-app">
<button @click="btnClick1">修改info1</button>
<button @click="btnClick2">修改info2</button>
</template>
<script src="../js/vue.js"></script>
<script>
const App = {
template: '#my-app',
data() {
return {
info: {
name: "why",
age:"19"
}
}
},
watch: {
info(newValue, oldValue) {
console.log(newValue, oldValue);
}
},
methods: {
btnClick1() {
this.info.name = "kobe";
},
btnClick2() {
this.info= {name:"jack"};
}
}
}
Vue.createApp(App).mount('#app');
</script>
处理方法
深度监听
(注意深浅拷贝情况)
- handle:watch中需要具体执行的方法。
- deep:true深度检测。例如数组对象中的某个属性改变执行handle方法。
高级监听:immediate:true立即执行handle方法(首次加载、刷新、数据改变)都会执行,缺点监听不到对象属性中发生的改变。
- 这个时候无论后面数据是否有变化,侦听的函数都会有限执行一次;
watch: {
info: {
handler(newValue, oldValue)
{
console.log(newValue, oldValue);
},
deep: true
}
}
监听对象某一个具体属性
来自vue2文档
watch:{
'info.name': function(newValue, oldValue) {
console.log(newValue, oldValue);
}
}
$watch 的API
- 我们可以在created的生命周期中,使用 this.$watchs 来侦听;
-
- 第一个参数是要侦听的源;
- 第二个参数是侦听的回调函数callback;
- 第三个参数是额外的其他选项,比如deep、immediate;
created() {
this.$watch('message', function(newValue, oldValue) {
console.log(newValue, oldValue);
},
{
deep: true,
immediate: true
}
}
watch与computed的区别
- 功能上:computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。
- 是否调用缓存:computed中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取,而watch在每次监听的值发生变化的时候都会执行回调。
- 是否调用return:computed中的函数必须要用return返回,watch中的函数不是必须要用return。
- computed默认第一次加载的时候就开始监听;watch默认第一次加载不做监听,如果需要第一次加载做监听,添加immediate属性,设置为true(immediate:true)
- computed不支持异步,当computed内有异步操作时是无法监听数据变化的,它的值会根据它所依赖的属性动态计算出来,并且计算结果会被缓存起来,只有当依赖的属性发生变化时才会重新计算。因此,computed届性必须是同步的,否则无法保证计算结果的正确性和稳定性。
- watch支持异步操作,watch属性是用来监听效据变化的,它可以通过配置回调函效来响应效据变化,并且这个回调函数可以是异步的。Watch属性的作用是在数据发生变化时执行一些操作,它不需要返回值,因此可以使用异步操作
- 使用场景:computed----当一个属性受多个属性影响的时候,使用computed-----购物车商品结算。watch–当一条数据影响多条数据的时候,使用watch-----搜索框.