Vue计算属性

本是古典 何须时尚 2022-10-19 05:31 118阅读 0赞

文章目录

    • 1、计算属性的定义
    • 2、计算属性的缓存
    • 3、v-for和v-if一起使用的替代方案
    • 4、实例:购物车的实现

1、计算属性的定义

  表达式的逻辑过于复杂的时候,应当考虑使用计算属性。计算属性是以函数形式,在选项对象的computed选项中定义。我们将字符串翻转的功能用计算属性实现,代码如下:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. <div id="app">
  11. <p>原始字符串:{
  12. {message}}</p>
  13. <p>计算后的反转字符串:{
  14. {reversedMessage}}</p>
  15. </div>
  16. <script src="https://unpkg.com/vue@next"></script>
  17. <script> const vm=Vue.createApp({ data(){ return{ message:'Hello,Java无难事!' } }, computed:{ //计算属性的getter reversedMessage(){ return this.message.split('').reverse().join(''); } } }).mount('#app'); </script>
  18. </body>
  19. </html>

渲染结果:
在这里插入图片描述

当message属性的值改变时,reversedMessage的值也会自动更新,并且会自动同步更新DOM部分。在浏览器的Console窗口中修改vm.message的值,可以发现reversedMessage的值也会随之改变。

  计算属性默认只有getter,因此是泵你直接修改计算属性的,如果需要,则可以提供一个setter,代码如下所示:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. <div id="app">
  11. <p>First name:<input type="text" v-model="firstName"></p>
  12. <p>Last name:<input type="text" v-model="lastName"></p>
  13. <p>{
  14. {fullName}}</p>
  15. </div>
  16. <script src="https://unpkg.com/vue@next"></script>
  17. <script> const vm=Vue.createApp({ data(){ return{ firstName:'Smith', lastName:'Will' } }, computed:{ fullName:{ //getter get(){ return this.firstName+' '+this.lastName }, //setter set(newValue){ let names=newValue.split(' '); this.firstName=names[0]; this.lastName=names[names.length-1]; } } } }).mount('#app'); </script>
  18. </body>
  19. </html>

渲染结果:
在这里插入图片描述
在这里插入图片描述

任意修改firstName和lastName的值,fullName的值也会自动更新,这是调用它的getter()函数实现的。在浏览器的Console窗口中输入vm.fullName=“Bruce Willis”,可以看到firstName和lastName的值也同时发生了改变,这是调用fullName的setter函数实现的。

2、计算属性的缓存

  复杂的表达式也可以放到方法中实现,然后在绑定表达式中调用方法即可。
翻转字符串也可以用下面的代码实现:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. <div id="app">
  11. <p>原始字符串:{
  12. {message}}</p>
  13. <p>计算后的反转字符串:{
  14. {reversedMessage()}}</p>
  15. </div>
  16. <script src="https://unpkg.com/vue@next"></script>
  17. <script> const vm=Vue.createApp({ data(){ return{ message:'Hello,Vue.js无难事!' } }, methods:{ reversedMessage(){ return this.message.split('').reverse().join(''); } } }).mount('#app'); </script>
  18. </body>
  19. </html>

既然使用方法能够实现与计算属性相同的结果,那么我们还有必要使用计算属性吗?
  答案是有必要,因为计算属性是基于它的响应式依赖进行缓存的,只有在计算属性的相关响应式依赖发生改变时才会更新值。这就意味着只要message还没有发生改变,多次访问reversedMessage计算属性会立即返回之前的计算结果,而不会再次执行函数;而如果采用方法,那么不管什么时候访问reversedMessage(),该方法都会被调用。

3、v-for和v-if一起使用的替代方案

  在渲染列表时,根据v-if指令的条件表达式的计算结果过滤列表中不满足条件的列表项。实际上,使用计算属性完成这个功能会更好一些。
  Vue.js的作者不建议将v-for和v-if一起使用,因为即使由于v-if指令的使用只渲染了部分元素,但在每次重新渲染的时候仍然要遍历整个列表,而不论渲染的元素内容是否发生了改变。
  采用计算属性过滤后再遍历,可以获得以下好处:

  • 过滤后的列表只会在plans数组发生相关变化时才会被重新计算,过滤更高效。
  • 使用v-for=”plan in completedPlans”之后,在渲染的时候只遍历已完成的计划,渲染更高效。
  • 解耦渲染层的逻辑,可维护性更强

代码如下:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>v-for与计算属性</title>
  8. </head>
  9. <body>
  10. <div id="app">
  11. <h1>已完成的工作计划</h1>
  12. <ul>
  13. <li v-for="plan in completedPlans">
  14. {
  15. {plan.content}}
  16. </li>
  17. </ul>
  18. <h1>未完成的工作计划</h1>
  19. <ul>
  20. <li v-for="plan in incompletePlans">
  21. {
  22. {plan.content}}
  23. </li>
  24. </ul>
  25. </div>
  26. <script src="https://unpkg.com/vue@next"></script>
  27. <script> const vm=Vue.createApp({ data(){ return{ plans:[ { content:'写《Java无难事》',isComplete:false}, { content:'买菜',isComplete:true}, { content:'写PPT',isComplete:false}, { content:'做饭',isComplete:true}, { content:'打羽毛球',isComplete:false} ] } }, computed:{ completedPlans(){ return this.plans.filter(plan=>plan.isComplete); }, incompletePlans(){ return this.plans.filter(plan=>!plan.isComplete); } } }).mount('#app'); </script>
  28. </body>
  29. </html>

在这里插入图片描述

4、实例:购物车的实现

  要实现一个购物车案例,当然得有商品信息,为了简化,我们直接在代码中给出所有的商品信息。在组件实例的data选项中定义数据。
  组件实例的data选项:

  1. data(){
  2. return{
  3. books:[
  4. {
  5. id:1,
  6. title:'Java无难事',
  7. price:188,
  8. count:1
  9. },{
  10. id:2,
  11. title:'VC++深入详解',
  12. price:168,
  13. count:1
  14. },{
  15. id:3,
  16. title:'Servlet/JSP深入详解',
  17. price:139,
  18. count:1
  19. }
  20. ]
  21. }
  22. }

  购物车中的单项商品金额是动态的,是由商品单价和商品的数量相乘得到的。此外,所有商品的总价也是动态的,是所有商品价格相加得到的,所以这两种数据就不适合在book对象的属性中定义了。
  采用方法来实现单项商品金额,采用计算属性实现总价,删除操作的事件处理器也定义为一个方法。

  1. methods:{
  2. itemPrice(price,count){
  3. return price*count;
  4. },
  5. deleteItem(index){
  6. this.books.splice(index,1);
  7. }
  8. }

  说明:单项商品金额的实现方式可以有很多种,本例采用组件实例的方法实现只是为了简单。

使用v-for指令输出商品信息

  1. <div id="app" v-cloak>
  2. <table>
  3. <tr>
  4. <th>序号</th>
  5. <th>商品名称</th>
  6. <th>单价</th>
  7. <th>数量</th>
  8. <th>金额</th>
  9. <th>操作</th>
  10. </tr>
  11. <tr v-for="(book,index) in books" :key="book.id">
  12. <td>{
  13. {book.id}}</td>
  14. <td>{
  15. {book.title}}</td>
  16. <td>{
  17. {book.price}}</td>
  18. <td>
  19. <button v-bind:disabled="book.count===0" v-on:click="book.count-=1">
  20. -
  21. </button>
  22. <button v-on:click="book.count+=1">+</button>
  23. </td>
  24. <td>
  25. {
  26. {itemPrice(book.price,book.count)}}
  27. </td>
  28. <td>
  29. <button @click="deleteItem(index)">删除</button>
  30. </td>
  31. </tr>
  32. </table>
  33. <span>总价¥{
  34. {totalPrice}}</span>
  35. </div>

说明:
(1)在<div>元素中,我们使用了v-cloak指令避免页面加载时的闪烁问题,当然,这需要和CSS样式规则[v-cloak]{display:none}一起使用。
(2)使用v-for指令时,我们同时使用了key属性(采用了v-bind的简写语法)。
(3)商品数量的左右两边各添加了一个减号和加号按钮,用于递减和递增商品数量,当商品数量为0时,通过v-bind:disabled="book.count===0"禁用按钮。此外,这两个按钮的功能都很简单,所以在使用v-on指令时,没有绑定click事件处理方法,而是直接使用了JavaScript语句。
(4)单项商品的价格通过调用itemPrice()方法输出。
(5)所有商品总价通过计算属性totalPrice输出。
(6)单项商品的删除通过v-on指令(采用了间歇语法)绑定deleteItem()方法实现。
完整代码如下:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>购物车</title>
  8. <style> body { width: 600px; } table { border: 1px solid black; } table { width: 100%; } th { height: 50px; } th, td { border-bottom: 1px solid #ddd; text-align: center; } span { float: right; } [v-cloak] { display: none; } </style>
  9. </head>
  10. <body>
  11. <div id="app" v-cloak>
  12. <table>
  13. <tr>
  14. <th>序号</th>
  15. <th>商品名称</th>
  16. <th>单价</th>
  17. <th>数量</th>
  18. <th>金额</th>
  19. <th>操作</th>
  20. </tr>
  21. <tr v-for="(book,index) in books" :key="book.id">
  22. <td>{
  23. {book.id}}</td>
  24. <td>{
  25. {book.title}}</td>
  26. <td>{
  27. {book.price}}</td>
  28. <td>
  29. <button v-bind:disabled="book.count===0" v-on:click="book.count-=1">
  30. -
  31. </button>
  32. <button v-on:click="book.count+=1">+</button>
  33. </td>
  34. <td>
  35. {
  36. {itemPrice(book.price,book.count)}}
  37. </td>
  38. <td>
  39. <button @click="deleteItem(index)">删除</button>
  40. </td>
  41. </tr>
  42. </table>
  43. <span>总价¥{
  44. {totalPrice}}</span>
  45. </div>
  46. <script src="https://unpkg.com/vue@next"></script>
  47. <script> const vm=Vue.createApp({ data(){ return{ books:[ { id:1, title:'Java无难事', price:188, count:1 },{ id:2, title:'VC++深入详解', price:168, count:1 },{ id:3, title:'Servlet/JSP深入详解', price:139, count:1 } ] } }, methods:{ itemPrice(price,count){ return price*count; }, deleteItem(index){ this.books.splice(index,1); } }, computed:{ totalPrice(){ let total=0; for(let book of this.books){ total+=book.price*book.count; } return total; } } }).mount('#app'); </script>
  48. </body>
  49. </html>

渲染结果:
在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,118人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Vue 计算属性

    简介 构造器的 computed 选项,用于定义 Vue 实例的计算属性。 虽然模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。如果在模板中放入太多的逻...

    相关 Vue 计算属性

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

    相关 Vue计算属性

    计算属性就是当其所依赖的属性的值发生变化的时候,这个属性的值会自动更新,与之相关的东西也会自己更新。计算属性可以完成各种复杂的逻辑,但是最终都要返回一个结果。计算属性可以依赖多

    相关 Vue计算属性

    计算属性关键词: computed。 计算属性在处理一些复杂逻辑时是很有用的。 可以看下以下反转字符串的例子: <div id="app"> <p>原

    相关 Vue计算属性

    计算属性   模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如: <div id="example