1-4.Vue 计算属性

1. 前言

本节介绍计算属性的使用方法。包括什么是计算属性,计算属性的特点,还有计算属性和方法在实际使用中的区别。其中重点掌握计算属性和方法的区别,了解它之后,才能在日常工作中灵活使用计算属性和方法。

2. 官方定义

计算属性,就是当其依赖属性的值发生变化时,这个属性的值会自动更新,与之相关的 DOM 部分也会同步自动更新。— 官方定义

计算属性实际上是一个方法,它可以完成各种复杂的逻辑,包括运算、函数调用等,并最终返回一个值。之前的章节中介绍了模版插值的语法,我们知道模板内的可以使用表达式进行计算,例如:{{ count * number }}。但有时候我们的计算逻辑并非如此简单,当模板中放入太多的复杂逻辑会让模板过于繁琐且难以维护。计算属性 computed 的使用可以解决此类问题。 computed 在项目中会大量使用,在使用时需要注意的是 computed 必须有一个返回值。使用 computed 并不难,难点在于如何编写其内部的复杂逻辑。

3. 写一个计算属性

前面介绍了什么是计算属性,那么怎么去定义一个计算属性呢?让我们先来看一段代码:实例演示

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<h1>商品数量:{{count}}</h1>
<h1>商品单价:{{unitPrice}}</h1>
<h1>商品总价:{{totalPrice()}}</h1>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
count: 10,
unitPrice: 24
},
methods: {
totalPrice() {
return this.count * this.unitPrice
}
}
})
</script>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app"> 
    <h1>商品数量:{{count}} 个</h1> 
    <h1>商品单价:{{unitPrice}} 元</h1> 
    <h1>商品总价:{{totalPrice()}} 元</h1> 
  </div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
 var vm = new Vue({
  el: '#app',
  data: {
    count: 10,
    unitPrice: 24
  },
  methods: {
    totalPrice() {
      return this.count * this.unitPrice
    }
  }
})
</script>
</html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> <h1>商品数量:{{count}} 个</h1> <h1>商品单价:{{unitPrice}} 元</h1> <h1>商品总价:{{totalPrice()}} 元</h1> </div> </body> <script src="https://unpkg.com/vue/dist/vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { count: 10, unitPrice: 24 }, methods: { totalPrice() { return this.count * this.unitPrice } } }) </script> </html>

代码解释:上述例子中,模板语句中我们通过一定的逻辑运算得到了商品的总价。像这样的算法我们可以使用计算属性来实现,接下来我们用计算属性来改写这个例子:实例演示

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<h1>商品数量:{{count}}</h1>
<h1>商品单价:{{unitPrice}}</h1>
<h1>商品总价:{{totalPrice}}</h1>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
count: 10,
unitPrice: 24
},
computed: {
totalPrice() {
return this.count * this.unitPrice
}
}
})
</script>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app"> 
    <h1>商品数量:{{count}} 个</h1> 
    <h1>商品单价:{{unitPrice}} 元</h1> 
    <h1>商品总价:{{totalPrice}} 元</h1> 
  </div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
 var vm = new Vue({
  el: '#app',
  data: {
    count: 10,
    unitPrice: 24
  },
  computed: {
    totalPrice() {
      return this.count * this.unitPrice
    }
  }
})
</script>
</html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> <h1>商品数量:{{count}} 个</h1> <h1>商品单价:{{unitPrice}} 元</h1> <h1>商品总价:{{totalPrice}} 元</h1> </div> </body> <script src="https://unpkg.com/vue/dist/vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { count: 10, unitPrice: 24 }, computed: { totalPrice() { return this.count * this.unitPrice } } }) </script> </html>

代码解释:
第 14-16 行,我们定义了一个计算属性 totalPrice,它的返回值是商品的单价和数量相乘得到的总价,在 html 模板中,我们直接用插值表达式 {{ totalPrice }} 来获得商品的总价,然后渲染到页面上。

计算属性的值会根据其函数内部依赖的变化而重新计算。也就是说,在上面的例子中当 count 和 unitPrice 有任意一方发生改变时 totalPrice 都会随之更新,最后更新页面。我们通过下面的例子来验证这一点:实例演示

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<h1>商品数量:{{count}}</h1>
<h1>商品单价:{{unitPrice}}</h1>
<h1>商品总价:{{totalPrice}}</h1>
<button @click="changePrice">修改单价</button>
<button @click="changeCount">修改数量</button>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
count: 10,
unitPrice: 24
},
computed: {
totalPrice() {
return this.count * this.unitPrice
}
},
methods: {
changePrice() {
vm.unitPrice = vm.unitPrice + 1
},
changeCount() {
vm.count = vm.count + 1
}
}
})
</script>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app"> 
    <h1>商品数量:{{count}} 个</h1> 
    <h1>商品单价:{{unitPrice}} 元</h1> 
    <h1>商品总价:{{totalPrice}} 元</h1> 
    <button @click="changePrice">修改单价</button>
    <button @click="changeCount">修改数量</button>
  </div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
 var vm = new Vue({
  el: '#app',
  data: {
    count: 10,
    unitPrice: 24
  },
  computed: {
    totalPrice() {
      return this.count * this.unitPrice
    }
  },
  methods: {
    changePrice() {
      vm.unitPrice = vm.unitPrice + 1
    },
    changeCount() {
      vm.count = vm.count + 1
    }
  }
})
</script>
</html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> <h1>商品数量:{{count}} 个</h1> <h1>商品单价:{{unitPrice}} 元</h1> <h1>商品总价:{{totalPrice}} 元</h1> <button @click="changePrice">修改单价</button> <button @click="changeCount">修改数量</button> </div> </body> <script src="https://unpkg.com/vue/dist/vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { count: 10, unitPrice: 24 }, computed: { totalPrice() { return this.count * this.unitPrice } }, methods: { changePrice() { vm.unitPrice = vm.unitPrice + 1 }, changeCount() { vm.count = vm.count + 1 } } }) </script> </html>

代码解释:
第 5-7 行,我们在页面中加入了修改单价和修改数量的两个操作按钮,每次点击修改单价就对单价 unitPrice + 1,点击修改数量就对数量 count + 1。当我们每次点击时,可以发现商品总价的值都会发生改变,因此计算属性的值会随着依赖的变化而更新。

4. Getter 和 Setter

前面我们介绍了如何编写一个简单的计算属性,接下来我们介绍了一下如何通过 getter 和 setter 来编写一个复杂的计算属性。
每一个计算属性都包含一个 getter 和一个 setter,我们上面的两个示例都是计算属性的默认用法,只是利用了 getter 来读取。在你需要时,也可以提供一个 setter函数 , 当手动修改计算属性的值就像修改一个普通数据那样时,就会触发 setter函数,执行一些自定义的操作。实例演示

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<h1>全名: {{fullName}} </h1>
<h1>firstName: {{firstName}} </h1>
<h1>lastName: {{lastName}} </h1>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
firstName: '',
lastName: ''
},
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
})
</script>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app"> 
      <h1>全名: {{fullName}} </h1> 
      <h1>firstName: {{firstName}} </h1> 
      <h1>lastName: {{lastName}} </h1> 
    </div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
 var vm = new Vue({
  el: '#app',
  data: {
    firstName: '',
    lastName: ''
  },
  computed: {
    fullName: {
      // getter
      get: function () {
        return this.firstName + ' ' + this.lastName
      },
      // setter
      set: function (newValue) {
        var names = newValue.split(' ')
        this.firstName = names[0]
        this.lastName = names[names.length - 1]
      }
    }
  }
})
</script>
</html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> <h1>全名: {{fullName}} </h1> <h1>firstName: {{firstName}} </h1> <h1>lastName: {{lastName}} </h1> </div> </body> <script src="https://unpkg.com/vue/dist/vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { firstName: '', lastName: '' }, computed: { fullName: { // getter get: function () { return this.firstName + ' ' + this.lastName }, // setter set: function (newValue) { var names = newValue.split(' ') this.firstName = names[0] this.lastName = names[names.length - 1] } } } }) </script> </html>

代码解释:
上述代码中我们定义了一个 fullName 的计算属性,并定义了它的 getter 和 setter。
第 4-6行,setter: 每次修改 fullName 时将姓赋值给 firstName,将名赋值给 lastName。
第 8-11行,getter: 每次获取 fullName 时将 firstName 和 lastName 拼接后返回。
我们打开控制台,运行 vm.fullName = ‘John Doe’ 时 setter 会被调用,vm.firstName 和 vm.lastName 也会相应地被更新。在控制台输入 vm.firstName 回车可以看到它的值。

5. 计算属性 VS 方法

如果不使用计算属性,在 methods 里定义了一个方法,也可以实现相同的效果,甚至该方法还可以接受参数,使用起来更灵活。
例如:实例演示

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<h1>商品数量:{{count}}</h1>
<h1>商品单价:{{unitPrice}}</h1>
<h1>商品总价:{{totalPrice()}}</h1>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
count: 10,
unitPrice: 24
},
methods: {
totalPrice() {
return this.count * this.unitPrice
}
}
})
</script>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app"> 
    <h1>商品数量:{{count}} 个</h1> 
    <h1>商品单价:{{unitPrice}} 元</h1> 
    <h1>商品总价:{{totalPrice()}} 元</h1> 
  </div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
 var vm = new Vue({
  el: '#app',
  data: {
    count: 10,
    unitPrice: 24
  },
  methods: {
    totalPrice() {
      return this.count * this.unitPrice
    }
  }
})
</script>
</html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> <h1>商品数量:{{count}} 个</h1> <h1>商品单价:{{unitPrice}} 元</h1> <h1>商品总价:{{totalPrice()}} 元</h1> </div> </body> <script src="https://unpkg.com/vue/dist/vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { count: 10, unitPrice: 24 }, methods: { totalPrice() { return this.count * this.unitPrice } } }) </script> </html>

代码解释:
第 8-10 行,我们定义了一个方法 totalPrice,它的返回值是商品的单价和数量相乘得到的总价,在 html 模板中,我们直接用插值表达式 {{ totalPrice() }} 来获得商品的总价,然后渲染到页面上。

既然 methods 同样可以解决模板中复杂逻辑计算的问题,那么为什么还需要使用计算属性呢?

原因就是:计算属性是基于它的依赖缓存的。前面我们介绍过,计算属性的改变取决于其所依赖数据的变化,所以只要依赖数据不发生改变,计算属性就不会更新。当我们重复获取计算属性时它也不会重复计算,只会获取缓存的值。而我们每次调用 methods 都会重新计算一遍,这样将会消耗一部分性能。当然,如何你不希望对数据进行缓存,那么可以用方法来代替。

© 版权声明
THE END
喜欢点个赞支持一下吧
点赞0赏币 分享
Everyone has its disadvantage just like the god bites the apple. the bigger disadvantage you have, the more the god appreciate it.
每个人都会有缺陷,就像被上帝咬过的苹果,有的人缺陷比较大,正是因为上帝特别喜欢他的芬芳
评论交流 抢沙发

请登录后发表评论

    暂无评论内容