Vue.js 从零开始:computed

此篇後面会有点难懂,可以去看我的范例,更了解实际运作喔,各位加油!

computed 计算属性

computed大部分都是读取data资料经过运算後,在渲染到画面上:
https://ithelp.ithome.com.tw/upload/images/20210925/20118347AyqqYdxLu5.png

使用computed的好处是能让模板看起来简洁:

<div id='app'>
  <div>{{ one + two + three }}</div> //未使用computed
  <div>{{ run }}</div> //使用computed
</div>
const vm = Vue.createApp({
  data() {
    return {
      one: 1,
      two: 2,
      three: 3
    };
  },
  computed: {
    run() {
      return this.one + this.two + this.three;
    }
  }
});

vm.mount("#app");

{{ one + two + three }} 可以改成{{ run }},如果是使用methods就要改成{{ run() }},另外使用computed时开头一定要加上return


computedmethods 的差异?

<div id='app'>
  <div>
    <p>methods: {{ num() }}</p>
    <p>methods: {{ num() }}</p>
    <p>methods: {{ num() }}</p>
    <p>computes: {{ run }}</p>
    <p>computes: {{ run }}</p>
    <p>computes: {{ run }}</p>
  </div>
</div>
const vm = Vue.createApp({
  data() {
    return {
      count: 0,
      four: 4,
    }
  },
  methods: {
    num() {
      console.log('isMethods');
      return this.four + this.count;
    }
  },
  computed: {
    run() {
      console.log('isComputed');
      return this.four + this.count;
    }
  }
});

vm.mount('#app')

console.log:
https://ithelp.ithome.com.tw/upload/images/20210924/20118347ZGWxGr409F.png

模板区块一样是各三个,run只有执行一次,而num()却执行了三次,这是因为computed的特性,computed会将计算过的结果暂存起来,computed的更新条件是原始资料有变更才会更新。

如果有需要计算大量的功能,如果没有使用computed,每次调用将会消耗大量资源来计算,如果不需要暂存则改用methods代替。

另外computed里的function无法使用参数。


computed 常用技巧

<div id='app'>
  <input type="search" v-model="search">
  <ul>
    <li v-for="item in filter">
      {{ item.name }}-{{ item.price }}
    </li>
  </ul>
</div>
const vm = Vue.createApp({
  data() {
    return {
      search: '',
      products: [
        {
          name: '上衣',
          price: 500,
        },
        {
          name: '裤子',
          price: 700,
        },
        {
          name: '鞋子',
          price: 2000,
        },
        {
          name: '袜子',
          price: 450,
        },
      ],
    }
  },
  computed:{
    filter() {
      return this.products.filter(item => {
        return item.name.match(this.search);
      });
     },
  }
}).mount('#app')

input输入框输入任何字串都会执行回圈,文字如果部分相符,就会显示出来:
https://ithelp.ithome.com.tw/upload/images/20210925/20118347F5DX5txe4J.png
filter将每一笔调用出来。
match()当item.name的字串有符合input输入的文字就调用出来。

JavaScript match()


gettersetter

getter:将data资料取出computed运算完之後渲染到画面。
setter:把资料(以下范例使用methods)运算完,传回data

首先computed里面要改成物件形式(total),在物件里面新增get()的函式:

<div id="app">
    <ul>
        <li v-for="product in products">
        {{ product.name }} / {{ product.price }}
        <button type="button" @click="addToCart(product)">+</button>
        </li>
    </ul>
    <h3>total 的值:{{ total }}</h3>
    <h3>Computed Getter, Setter</h3>
    computed sum 的值:
    <input type="number" v-model.number="num">
    <button type="button" @click="total = num">更新</button>
    total 的值:{{ total }}<br>
    computed sum 的值::{{ sum }}
</div>
const App = {
    data() {
        return {
            products: [
            {
                name: '上衣',
                price: 300,            
            },
            {
                name: '裤子',
                price: 500,            
            },
            {
                name: '鞋子',
                price: 1500,           
            },
            {
                name: '帽子',
                price: 600,
            },
            ],
            carts: [],
            sum: 0,
            num: 20,
        }
    },
    computed: {
        total: {
            get() {
                let total = 0;
                this.carts.forEach(item => {
                    total += item.price;
                });
                return total;
            }
        },
    },
    methods: {
        addToCart(product) {
            this.carts.push(product);
        },
    }
};
Vue.createApp(App).mount('#app');

input v-model.number="num"已经绑定data的num,预期是点击更新(@click="total=num")会将total的值变成num
https://ithelp.ithome.com.tw/upload/images/20210925/20118347XgutnBPLcr.png
[Vue warn]: Write operation failed: computed property "total" is readonly。此值只能被读取。

这时就要使用set()函式,将他加入到computed里面的total物件:

computed: {
        total: {
            get() {
                let total = 0;
                this.carts.forEach(item => {
                    total += item.price;
                });
                return this.sum || total;
                // 如果 this.sum 有值就回传,没有值就使用 total 的值。
            },
            set(val) {
              console.log('val') // num 的20
              this.sum = val; // num 的20,传回 data 的 sum
            }
        },
    },

CodePen[完整范例]
整个流程:
1.get()会先执行一次,computed会先自己计算一次并暂存。
2.点击帽子+把金额带到total,再次触发get(),total的值变成600。
2.点击更新触发set(val)函式,数字20传回this.sum,同时{{ sum }} 变成 20。
3.最後再次触发get()把total的值也变成 20。

可以打开CodePen观察console.log的变化,可以发现gettersetter是分开进行的。


如上述有任何错误,欢迎指教,感谢你的收看,明天见。

/images/emoticon/emoticon14.gif


参考资料

六角学院
重新认识 Vue.js
Vue.js


<<:  16 综观各校资工系修课蓝图

>>:  [Day 30] 资料产品开发实务 - 完结撒花!

30天程序语言研究

今天是30天程序语言研究的第十九天,由於深度学习老师多让我们上了python的进阶课程里面包括之前没...

RxJS 工具类型 Operators (1) - tap / toArray / delay / delayWhen

今天要介绍的是「工具类型」的 Operators,也都不太困难,很好理解,继续轻松学习吧! tap ...

day18 kotlin - flow基本操作

我会从文档中挑几个重要的出来讲,但不会是全部,我会着重一些基本的中间操作,异常,取消,dispatc...

[day29]优化架构-订单留存及检核(2)

倒数两天,不知道这次铁人赛结束後,还能不能修改内容 想做的东西很多,未来希望能补充一些东西,今天出差...

Day 28 - 实战演练 — Pagination

Pagination 今天要实作的只是一个最基本的 Pagination,而我个人觉得在处理换页时...