Vue+TypeScript中處理computed方式
什么是computed
「computed」 是Vue中提供的一個(gè)計(jì)算屬性。它被混入到Vue實(shí)例中,所有的getter和setter的this上下文自動(dòng)的綁定為Vue實(shí)例。計(jì)算屬性的結(jié)果會(huì)被緩存,除非依賴的響應(yīng)式property變化才會(huì)從新計(jì)算。
computed的用途
我們可以使用 「computed」 對已有的屬性數(shù)據(jù)進(jìn)行加工處理,得到我們的目標(biāo)數(shù)據(jù)。
在TypeScript怎么用
在 「vue-class-component」 中分別為props,watch等提供了對應(yīng)的裝飾器,而 「computed」 卻沒有對應(yīng)的裝飾器提供。
在官網(wǎng)的實(shí)例中,「computed」 的功能是通過 「get」 實(shí)現(xiàn)的。
<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>
另一種方案
在實(shí)際項(xiàng)目中,將組件修改為TypeScript后,使用 get 實(shí)現(xiàn)計(jì)算屬性,瀏覽器控制臺(tái)提示data是非響應(yīng)式的,數(shù)據(jù)無法顯示。組件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>
鑒于這個(gè)問題,使用創(chuàng)建中間變量的方式進(jìn)行解決。組件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正確使用方式
最近面試中,遇到一個(gè)小伙子,談到了vue中的computed和watch區(qū)別,最后得到了一個(gè)讓我瞠目結(jié)舌的答案,只用watch,從不用computed
模板內(nèi)的表達(dá)式非常便利,但是設(shè)計(jì)它們的初衷是用于簡單運(yùn)算的。在模板中放入太多的邏輯會(huì)讓模板過重且難以維護(hù),所以,對于復(fù)雜邏輯,vue 提倡使用計(jì)算屬性。需要特別說明:計(jì)算屬性的 getter 函數(shù)是沒有副作用 (side effect) 的,這使它更易于測試和理解 — from Vue計(jì)算屬性
討論 computed 和 watch 之間的區(qū)別前,我們先看下 computed 和 methods 有何區(qū)別?
computed or methods
理論上,computed 所有實(shí)現(xiàn)可以使用 methods 完全替換。
<p>Reversed message: "{{ reversedMessage() }}"</p> <p>Reversed message: "{{ reversedMessage }}"</p>
// 計(jì)算屬性 computed: { reversedMessage () { return this.message.split('').reverse().join('') } } // 方法 methods: { reversedMessage: function () { return this.message.split('').reverse().join('') } }
計(jì)算屬性是基于它們的響應(yīng)式依賴進(jìn)行緩存的。只在相關(guān)響應(yīng)式依賴發(fā)生改變時(shí)它們才會(huì)重新求值。這就意味著只要 message 還沒有發(fā)生改變,多次訪問 reversedMessage計(jì)算屬性會(huì)立即返回之前的計(jì)算結(jié)果,而不必再次執(zhí)行函數(shù)。而方法卻會(huì)執(zhí)行。
這也同樣意味著下面的計(jì)算屬性將不再更新,因?yàn)?Date.now() 不是響應(yīng)式依賴:
computed: { now: function () { return Date.now() } }
我們?yōu)槭裁葱枰彺??假設(shè)我們有一個(gè)性能開銷比較大的計(jì)算屬性 A,它需要遍歷一個(gè)巨大的數(shù)組并做大量的計(jì)算。然后我們可能有其他的計(jì)算屬性依賴于 A 。如果沒有緩存,我們將不可避免的多次執(zhí)行 A 的 getter!如果你不希望有緩存,請用方法來替代。
相同之處: computed 和 methods 將被混入到 Vue 實(shí)例中。vm.reversedMessage/vm.reversedMessage() 即可獲取相關(guān)計(jì)算屬性/方法。
接下來,看下 computed 和 watch 有何區(qū)別?
computed or watch
Vue 提供了一種更通用的方式來觀察和響應(yīng) Vue 實(shí)例上的數(shù)據(jù)變動(dòng):偵聽屬性。當(dāng)你有一些數(shù)據(jù)需要隨著其它數(shù)據(jù)變動(dòng)而變動(dòng)時(shí),你很容易濫用 watch,然而,通常更好的做法是使用計(jì)算屬性而不是命令式的 watch 回調(diào)。
當(dāng)需要在數(shù)據(jù)變化時(shí)執(zhí)行異步或開銷較大的操作時(shí), watch 方式是最有用的。其允許我們執(zhí)行異步操作 (訪問一個(gè) API),限制我們執(zhí)行該操作的頻率,并在我們得到最終結(jié)果前,設(shè)置中間狀態(tài)。這些都是計(jì)算屬性無法做到的。
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 反彈函數(shù) this.debouncedGetAnswer = _.debounce(this.getAnswer, 500) }
這樣來看,watch 完全可以替代 computed ?什么情況下,只能使用computed呢?
回顧 computed 最大特點(diǎn)就是緩存,所以上述問題可以轉(zhuǎn)換為:哪些情況下,我們需要依賴緩存?
示例:父組件給子組件傳值,值的類型為引用類型
父組件
<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>
現(xiàn)在有這樣一個(gè)需求,子組件中需要同時(shí)顯示改變前和改變后的值。
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>
查看結(jié)果,WTF,啥情況~~
問題在于,user為引用類型,且 watch 沒有做緩存,導(dǎo)致了修改的是同一個(gè)對象,所以,watch 方法中**val === olVal is true??!**
如何達(dá)到要求呢,這里我們就可以借用 computed 緩存的特性,來完成上述情況。
計(jì)算屬性的結(jié)果會(huì)被緩存,除非依賴的響應(yīng)式屬性變化才會(huì)重新計(jì)算。注意,如果某個(gè)依賴 (比如非響應(yīng)式屬性) 在該實(shí)例范疇之外,則計(jì)算屬性是不會(huì)被更新的。 — 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) 來創(chuàng)建新的引用!
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- vue3結(jié)合typescript中使用class封裝axios
- vue3+vite3+typescript實(shí)現(xiàn)驗(yàn)證碼功能及表單驗(yàn)證效果
- 使用Vite+Vue3+TypeScript?搭建開發(fā)腳手架的詳細(xì)過程
- vue?props使用typescript自定義類型的方法實(shí)例
- 基于Vue3+TypeScript的全局對象的注入和使用詳解
- Vue3+TypeScript+Vite使用require動(dòng)態(tài)引入圖片等靜態(tài)資源
- vue3+Pinia+TypeScript?實(shí)現(xiàn)封裝輪播圖組件
- vue項(xiàng)目中使用ts(typescript)入門教程
- vue3中如何使用vue-types
相關(guān)文章
Vue.js系列之項(xiàng)目結(jié)構(gòu)說明(2)
這篇文章主要介紹了Vue.js系列之項(xiàng)目結(jié)構(gòu)說明(2)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-01-01詳解win7 cmd執(zhí)行vue不是內(nèi)部命令的解決方法
這篇文章主要介紹了詳解win7 cmd執(zhí)行vue不是內(nèi)部命令的解決方法的相關(guān)資料,這里提供了解決問題的詳細(xì)步驟,具有一定的參考價(jià)值,需要的朋友可以參考下2017-07-07vue-cli安裝全過程(附帶cnpm安裝不成功及vue不是內(nèi)部命令)
這篇文章主要介紹了vue-cli安裝全過程(附帶cnpm安裝不成功及vue不是內(nèi)部命令),具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11