<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
「computed」 是Vue中提供的一個計算屬性。它被混入到Vue範例中,所有的getter和setter的this上下文自動的繫結為Vue範例。計算屬性的結果會被快取,除非依賴的響應式property變化才會從新計算。
我們可以使用 「computed」 對已有的屬性資料進行加工處理,得到我們的目標資料。
在 「vue-class-component」 中分別為props,watch等提供了對應的裝飾器,而 「computed」 卻沒有對應的裝飾器提供。
在官網的範例中,「computed」 的功能是通過 「get」 實現的。
<template> <input v-model="name"> </template> <script> import Vue from 'vue' import Component from 'vue-class-component' @Component export default class HelloWorld extends Vue { firstName = 'John' lastName = 'Doe' // Declared as computed property getter get name() { return this.firstName + ' ' + this.lastName } // Declared as computed property setter set name(value) { const splitted = value.split(' ') this.firstName = splitted[0] this.lastName = splitted[1] || '' } } </script>
在實際專案中,將元件修改為TypeScript後,使用 get 實現計算屬性,瀏覽器控制檯提示data是非響應式的,資料無法顯示。元件js版
<template> <el-table border :data="data" style="width: 100%;" height="400" @selection-change="selectChange"> <el-table-column type="selection" width="55"></el-table-column> <el-table-column prop="code" label="編碼"></el-table-column> <el-table-column prop="name" label="名稱"></el-table-column> </el-table> </template>
<script> export default { name: 'hierarchy-table', props: { value: { type: Array, required: true }, skipCodes: { type: Array } }, data() { return { }; }, computed: { data() { return this.skipCodes ? this.value.filter(it => !this.skipCodes.includes(it.code)) : this.value; } }, methods: { selectChange(selection) { this.$emit('selection-change', selection); } } }; </script>
鑑於這個問題,使用建立中間變數的方式進行解決。元件ts版
<template> <el-table border :data="data" style="width: 100%;" height="400" @selection-change="selectChange"> <el-table-column type="selection" width="55"></el-table-column> <el-table-column prop="code" label="編碼"></el-table-column> <el-table-column prop="name" label="名稱"></el-table-column> </el-table> </template>
<script lang="ts"> import { Component, Prop, Vue, Watch } from 'vue-property-decorator'; @Component export default class HierarchyTable extends Vue { data: any[] = []; @Prop({ type: Array, required: true }) value!: any; @Prop({ type: Array }) skipCodes: any; @Watch('value') valueChanged(val) { this.updateData(); } @Watch('skipCodes') skipCodesChanged() { this.updateData(); } updateData() { this.data = this.skipCodes ? this.value.filter(it => !this.skipCodes.includes(it.code)) : this.value; } selectChange(selection) { this.$emit('selection-change', selection); } } </script> <style scoped></style>
最近面試中,遇到一個小夥子,談到了vue中的computed和watch區別,最後得到了一個讓我瞠目結舌的答案,只用watch,從不用computed
模板內的表示式非常便利,但是設計它們的初衷是用於簡單運算的。在模板中放入太多的邏輯會讓模板過重且難以維護,所以,對於複雜邏輯,vue 提倡使用計算屬性。需要特別說明:計算屬性的 getter 函數是沒有副作用 (side effect) 的,這使它更易於測試和理解 — from Vue計算屬性
討論 computed 和 watch 之間的區別前,我們先看下 computed 和 methods 有何區別?
理論上,computed 所有實現可以使用 methods 完全替換。
<p>Reversed message: "{{ reversedMessage() }}"</p> <p>Reversed message: "{{ reversedMessage }}"</p>
// 計算屬性 computed: { reversedMessage () { return this.message.split('').reverse().join('') } } // 方法 methods: { reversedMessage: function () { return this.message.split('').reverse().join('') } }
計算屬性是基於它們的響應式依賴進行快取的。只在相關響應式依賴發生改變時它們才會重新求值。這就意味著只要 message 還沒有發生改變,多次存取 reversedMessage計算屬性會立即返回之前的計算結果,而不必再次執行函數。而方法卻會執行。
這也同樣意味著下面的計算屬性將不再更新,因為 Date.now() 不是響應式依賴:
computed: { now: function () { return Date.now() } }
我們為什麼需要快取?假設我們有一個效能開銷比較大的計算屬性 A,它需要遍歷一個巨大的陣列並做大量的計算。然後我們可能有其他的計算屬性依賴於 A 。如果沒有快取,我們將不可避免的多次執行 A 的 getter!如果你不希望有快取,請用方法來替代。
相同之處: computed 和 methods 將被混入到 Vue 範例中。vm.reversedMessage/vm.reversedMessage() 即可獲取相關計算屬性/方法。
接下來,看下 computed 和 watch 有何區別?
Vue 提供了一種更通用的方式來觀察和響應 Vue 範例上的資料變動:偵聽屬性。當你有一些資料需要隨著其它資料變動而變動時,你很容易濫用 watch,然而,通常更好的做法是使用計算屬性而不是命令式的 watch 回撥。
當需要在資料變化時執行非同步或開銷較大的操作時, watch 方式是最有用的。其允許我們執行非同步操作 (存取一個 API),限制我們執行該操作的頻率,並在我們得到最終結果前,設定中間狀態。這些都是計算屬性無法做到的。
methods: { getAnswer: function () { this.answer = 'Thinking...' var vm = this axios.get('https://yesno.wtf/api') .then(function (response) { vm.answer = _.capitalize(response.data.answer) }) .catch(function (error) { vm.answer = 'Error! Could not reach the API. ' + error }) } }, created: function () { // debounce 反彈函數 this.debouncedGetAnswer = _.debounce(this.getAnswer, 500) }
這樣來看,watch 完全可以替代 computed ?什麼情況下,只能使用computed呢?
回顧 computed 最大特點就是快取,所以上述問題可以轉換為:哪些情況下,我們需要依賴快取?
範例:父元件給子元件傳值,值的型別為參照型別
父元件
<template> <div> <child :user="user"></child> <label for="user">parent:</label> <input id="user" type="text" v-model="user.name"> </div> </template> <script> import Child from './child.vue' export default { data () { return { user: { name: 'ligang' } } }, components: { Child } } </script>
子元件
<template> <div>child: {{user}}</div> </template> <script> export default { name: 'child', props: ['user'] } </script>
現在有這樣一個需求,子元件中需要同時顯示改變前和改變後的值。
So Easy,只需要在 watch 中儲存 oldVal 即可。
<template> <div> <div>child:</div> <div>修改前:{{oldUser}} 修改後:{{user}}</div> </div> </template> <script> export default { name: 'child', props: ['user'], data () { return { oldUser: {} } }, watch: { user: { handler (val, oldVal) { this.oldUser = oldVal || val }, deep: true, immediate: true } } } </script>
檢視結果,WTF,啥情況~~
問題在於,user為參照型別,且 watch 沒有做快取,導致了修改的是同一個物件,所以,watch 方法中**val === olVal is true!!**
如何達到要求呢,這裡我們就可以借用 computed 快取的特性,來完成上述情況。
計算屬性的結果會被快取,除非依賴的響應式屬性變化才會重新計算。注意,如果某個依賴 (比如非響應式屬性) 在該範例範疇之外,則計算屬性是不會被更新的。 — vue-computed-api
<template> <div> <div>child:</div> <div>修改前:{{oldUser}} 修改後:{{user}}</div> </div> </template> <script> export default { name: 'child', props: ['user'], data () { return { oldUser: {} } }, // 快取 userInfo computed: { userInfo () { return { ...this.user } } }, watch: { userInfo: { handler (val, oldVal) { this.oldUser = oldVal || val }, deep: true, immediate: true } } } </script>
需要注意:{ ...this.user } 或者使用 Object.assign({}, this.user) 來建立新的參照!
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45