区别:
computed 支持缓存 依赖其他属性值 只要当依赖的属性值发生改变的时候 才会从新计算 而且computed不支持异步 如何里面有异步的话 那么无法监听数据改变,watch 不支持缓存 监听一个属性值 当属性值发生改变的时候 watch触发 支持异步 computed和watch都是依赖vue追踪机制为基础
一、计算属性(computed)
1、计算属性的特点
- 支持 数据缓存——页面重新渲染时,只有当依赖的数据发生了改变,才会从新开始计算。
- 减少模板中计算逻辑,可以提升性能,调用很多次,只需要计算一次,保存在缓存中。
- 依赖“响应式数据”。
2、不使用计算属性的缺点
<div id="app">
<!-- 正常绑定数据 -->
{{msg}}
<!-- 对数据进行逻辑处理, 反向字符串 -->
{{msg.split("").reverse().join("")}}
<!-- 多次使用功能反向逻辑 -->
{{msg.split("").reverse().join("")}}
{{msg.split("").reverse().join("")}}
{{msg.split("").reverse().join("")}}
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
msg: "helloWord",
}
})
</script>
通过示例我们可以看到如果需要多次使用这个逻辑时就不那么方便了,而且每次都要从新计算
同时将太多的逻辑放入模板中处理,就会使得模板很臃肿,这样不利于代码的维护。
3、使用methods的缺点
我们首先可能会想到使用方法, 把这些复杂的逻辑定义为一个方法, 然后通过多次调用这个方法来达到逻辑复用的目的,但是也是有缺点的
<div id="app">
<!-- 多次调用方法复用代码逻辑 -->
{{ reverseStr() }}
{{ reverseStr() }}
{{ reverseStr() }}
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
msg: "helloWord",
},
methods: {
reverseStr(){
return this.msg.split("").reverse().join("")
}
}
})
</script>
其实我们这样可以达到复用的目的, 但是我们测试就会发现,函数在每一次调用的时候都会执行, 都会重新计算, 如果调用100次,函数就会执行100次, 对于性能不是特别好, 因为每一次的结果都是一样的,所以就有了计算属性
4、如何使用computed
Vue给我们提供了一个计算属性computed, 计算属性中的方法也是函数, 但是跟普通方法不同,
计算属性会将计算的结果挂载到Vue实例对象的属性上. 这样每次调用的时候,都是在调用Vue实例的属性。
<div id="app">
<!-- 利用计算属性来处理逻辑 -->
{{ reverseMsg }}
{{ reverseMsg }
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
msg: "helloWord",
},
computed:{
reverseMsg(){
console.log("执行") //这里可以测试执行了几次
return this.msg.split("").reverse().join("")
}
}
})
</script>
这里我们在Vue 的 computed 属性中定义了一个方法 reverseMsg , Vue会自动计算这个方法的结果, 不需要我们自己调用, vue会将计算后的结果添加给 Vue 实例对象的同名属性. 这就是我们所说的计算属性
因为是属性的关系,我们在{{}}中使用不需要添加()执行, 就跟我们平时调用data 属性中的数据一样使用就好
4、数据发生变化
<div id="app">
<!-- 利用计算属性来处理逻辑 -->
{{ reverseMsg }}
{{ reverseMsg }}
<!-- 点击按钮改变数据 -->
<button @click="changeMsg">点击改变数据</button>
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
msg: "helloword",
},
methods: {
changeMsg(){
this.msg = "orderWord"
}
},
computed:{
reverseMsg(){
console.log("执行")
return this.msg.split("").reverse().join("")
}
}
})
</script>
当我们点击改变数据按钮的时候, 数据发生变化, 数据一旦发生变化,就会自动触发依赖这个数据的计算属性的方法, 通过计算得到的结果将会覆盖原来属性的结果, 也就会重现渲染页面结果
5. 计算属性的getter和setter
其实计算由两部分组成,为get和set(不能只写set),一般情况下通过js赋值影响其他人或者表单元素设置值的时候会调用set方法
其实想想就能理解, 对象的属性, 获取的时候不就是get 当你改变对象属性的值,不就是重新赋值了嘛,也就是set啊
{
computed:{
// 计算属性写成对象,就需要手动设置get方法,set方法
sum:{
get(){
// 获取时调用的方法
},
set(val){
// 设置时调用
}
},
// 如果计算属性写成函数,默认调用的就是get方法,没有set方法
sum(){
}
}
}
6.get语法
计算属性默认只有 get ,不过在需要时你也可以提供一个 set
我们默认的计算就是只有get操作
<div id="app">
<!-- 显示计算属性结果-->
<div>
<input type="text" v-model="firstName">
</div>
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
firstName:"Foo",
lastName: "Bar",
},
computed:{
// 这里Fullname只有get功能
fullName(){
return this.firstName + ' ' + this.lastName
}
}
})
</script>
7.set语法
如果我想改变计算属性的值,能不能反向的修改firstname 和lastname的值呢, 发现不可以,因为我们没有添加set计算属性设置
如果想添加计算属性的set功能,我们就得改变咱们计算属性的写法
<script>
const vm = new Vue({
el: "#app",
data: {
firstName:"Foo",
lastName: "Bar"
},
computed:{
fullName:{
// 计算属性的get
get(){
console.log("get")
return this.firstName + ' ' + this.lastName
},
// 计算属性的set, set是设置,设置就需要新值传入
set(value){
console.log("set")
let fullNameArr = value.split(" ");
this.firstName = fullNameArr[0] ? fullNameArr[0]: '';
this.lastName = fullNameArr[1] ? fullNameArr[1]: '';
}
}
}
})
</script>
二、监听(watch)
相信大家在开发项目中,有时候会遇到一些需求,是当一个数据改变之后进行一些操作,这个时候有些人会设置一个定时器,周期性的去循环访问,当发现数据发生了改变后执行操作。但是这种操作方式会导致系统资源的浪费,以及更新的不及时等。因此vue通过watch(侦听器)提供了一个更通用的方法来响应数据的变化,当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
1.watch的基础使用
下方代码是watch的一个基础使用,可以看到当第一次进入页面的时候,并没有触发,而点击按钮的时候,name的值发生了改变,被watch监听到,因此执行了下面的输出逻辑。
<template>
<div class="home">
<el-button @click="name='李四'">改变</el-button>
</div>
</template>
<script>
export default {
data() {
return {
name: '张三'
}
},
//使用watch监听器,当不点击按钮的时候不会触发
watch: {
name(newValue, oldValue) { //这里的第一个参数是改变后的值,第二个参数是原来的值
console.log('改后的值是:' + newValue)
console.log('原来的值是:' + oldValue)
}
}
}
</script>
2.deep属性
在使用watch的过程中,如果定义了一个对象,这时候我们会发现使用一般的watch监听,是无法监听对象内部的改变的,这时候我们需要使用depp属性进行一个深度监听。
比如在以下代码中,因为watch所监听的是一个person对象,当点击按钮改变之后,会发现没有任何执行效果。也就是监听失败。
<template>
<div class="home">
<el-button @click="person.name='李四'">改变</el-button>
</div>
</template>
<script>
export default {
data() {
return {
person: {
name:'张三'
}
}
},
//使用watch监听器,当不点击按钮的时候不会触发
watch: {
person: {
handler(newValue, oldValue) {//这里的第一个参数是改变后的值,第二个参数是原来的值
console.log('改后的值是:' + newValue.name)
console.log('原来的值是:' + oldValue.name)
}
}
}
}
</script>
所以我们在上述代码中加入depp:true,形成下面的代码,这时候我们可以在控制台看到是能够成功执行的。
<template>
<div class="home">
<el-button @click="person.name='李四'">改变</el-button>
</div>
</template>
<script>
export default {
data() {
return {
person: {
name:'张三'
}
}
},
//使用watch监听器,当不点击按钮的时候不会触发
watch: {
newPerson: {
handler(newValue, oldValue) {//这里的第一个参数是改变后的值,第二个参数是原来的值
console.log('改后的值是:' + newValue.name)
console.log('原来的值是:' + oldValue.name)
},
deep:true,//深度监听
}
},
computed:{
// 使用计算属性进行深拷贝
newPerson(){
return JSON.parse(JSON.stringify(this.person))
}
}
}
</script>