Computed 為 Vue 的獨門武功,當 Model 改變時,Computed 可以 Reactive 隨之改變,是 Vue 的 Reactive Programming 實踐。
Version
Vue 2.6.11
Computed
Model 為 Sam
,但所顯示的與 Model 不同,此時可透過 Computed 加以修飾。
Implicit Argument
<template>
<div>
{{ greeting }}
</div>
</template>
<script>
let greeting = function() {
return `Hello ${this.name}`
}
export default {
name:'App',
data:() => ({
name: 'Sam'
}),
computed: {
greeting
}
}
</script>
第 2 行
<div>
{{ greeting }}
</div>
HTML template 綁定的 greeting
為 computed,而不是 model。
14 行
data:() => ({
name: 'Sam'
}),
在 data
宣告 name
model,其值為 Sam
。
17 行
computed: {
greeting
}
在 computed
宣告 greeting
computed,如同 data
一樣,computed
本質是 function。
第 8 行
let greeting = function() {
return `Hello ${this.name}`
}
實作 greeting
computed,以 implicit argument this
直接讀取 model,因此一定要使用 function expression。
當 name
model 改變時,greeting
computed 會 reactive 跟著改變。
Explicit Argument
<template>
<div>
{{ greeting }}
</div>
</template>
<script>
let greeting = function({ name }) {
return `Hello ${name}`
}
export default {
name:'App',
data:() => ({
name: 'Sam'
}),
computed: {
greeting
}
}
</script>
第 8 行
let greeting = function({ name }) {
return `Hello ${name}`
}
Implicit argument 方式雖然方便,但使用 this
是它的至命傷,這使得 computed 無法抽成 free function,也無法 Function Pipeline。
Computed 也支援 explicit argument 寫法,在 argument 內使用 object destructuring 取得 model。
Arrow Function
<template>
<div>
{{ greeting }}
</div>
</template>
<script>
let greeting = ({ name }) => `Hello ${name}`
export default {
name:'App',
data:() => ({
name: 'Sam'
}),
computed: {
greeting
}
}
</script>
第 8 行
let greeting = ({ name }) => `Hello ${name}`
既然沒使用 this
,就可安心使用 arrow function。
Function Pipeline
<template>
<div>
{{ greeting }}
</div>
</template>
<script>
import { pipe, prop, concat } from 'ramda'
let greeting = pipe(
prop('name'),
concat(`Hello `)
)
export default {
name:'App',
data:() => ({
name: 'Sam'
}),
computed: {
greeting
}
}
</script>
第 10 行
let greeting = pipe(
prop('name'),
concat(`Hello `)
)
既然 model 是來自 argument,可進一步使用 Ramda 的 prop()
使其 point-free。
Method
<template>
<div>
{{ greeting(name) }}
</div>
</template>
<script>
let greeting = name => `Hello ${name}`
export default {
name:'App',
data:() => ({
name: 'Sam'
}),
methods: {
greeting
}
}
</script>
第 2 行
<div>
{{ greeting(name) }}
</div>
Computed 的一個限制是不能自行傳遞 argument,若想傳遞 argument,則要使用 method。
15 行
methods: {
greeting
}
在 method
宣告 greeting
method,其本質也是 function。
第 8 行
let greeting = name => `Hello ${name}`
由於 method 使用 explicit argument,而沒使用 this
,因此可使用 arrow function。
Point-free
<template>
<div>
{{ greeting(name) }}
</div>
</template>
<script>
import { concat } from 'ramda'
let greeting = concat('Hello ')
export default {
name:'App',
data:() => ({
name: 'Sam'
}),
methods: {
greeting
}
}
</script>
10 行
let greeting = concat('Hello ')
由於 method 為 explicit argument,沒使用 this
為 pure function,因此也可使用 Ramda 的 concat()
使其 point-free。
Prop
<template>
<div>
<Greeting :name="name"></Greeting>
</div>
</template>
<script>
import Greeting from '@/components/Greeting'
export default {
name:'App',
components: {
Greeting
},
data:() => ({
name: 'Sam'
})
}
</script>
第 3 行
<Greeting :name="name"></Greeting>
Computed 雖然不能接受 explicit argument,但卻能接受 prop,將 name
model 以 prop 傳入 Greeting
component。
Greeting.vue
<template>
<div>{{ greeting }} </div>
</template>
<script>
let greeting = function() {
return `Hello ${this.name}`
}
export default {
name: 'Greeting',
props: {
name
},
computed: {
greeting
}
}
</script>
12 行
props: {
name
},
宣告 name
prop。
第 6 行
let greeting = function() {
return `Hello ${this.name}`
}
greeting
computed 可藉由 this
讀取 name
prop。
Conclusion
- Computed 傳統寫法是使用 implicit argument 讀取 model,這使得 computed 只能使用 function expression,且不方便抽成 free function 與使用 Function Pipeline
- Computed 後來也支援 explicit argument 寫法,這使得 computed 也能使用 arrow function 實現,也方便抽成 free function 與使用 Function Pipeline
- 若不帶 argument,computed 與 method 功能相同,優先考慮使用 computed,因為其有 cache,效能較 method 優
- Computed 雖然不能接受 argument,但卻能接受 prop,因此在建立自已的 component 時,computed 非常實用