Vue.js 的自我介紹中,只有說自己接近 MVVM 但不是嚴格的 MVVM。
我覺得只要會「自動更新畫面」就算是有 MVVM 的效果至於有沒有達到 MVVM pattern 的結構不用太計較。XDDD
接下來,我們來挑戰一個 computed 和 watch 的解釋,但是不一起比較,這次我們各別介紹,以免兩個人又再度難分難捨。
今天的文章比較短,為了避免觀念混淆,所以特別縮短篇幅,集中一個概念的方式介紹。
參考自官網的例子: https://vuejs.org/v2/guide/computed.html
這個例子很好,只是分開講更清楚,避免不細節用掃視的,想快速學習的朋友們,看圖說故事時造成誤會。
<template>
<div>
<div><input type="text" v-model="user.firstName"></input></div>
<div><input type="text" v-model="user.lastName"></input></div>
<div>{{ fullName }}</div>
</div>
</template>
export default {
name: 'demo',
data() {
return {
user: {
firstName: 'Foo',
lastName: 'Bar',
},
};
},
computed: {
fullName() {
return this.user.firstName + this.user.lastName;
},
}
}
在這個時候,想像一下 user
是來自 API 的 data。
fullName
對 API 來說是一個不存在的欄位。並且,這一個衍生資料只拿來顯示,不會寫入的資料,只透過其它欄位來改它。
至於它會連動畫面這件事,不用開發者操心,這件事就交給尤雨渓吧。我們只要負責看好文件寫 code 就好了。
如果,我們要設計一個 User 的物件
class User {
constructor() {
this.firstName = 'Foo';
this.lastName = 'Bar';
}
getFullName() {
return this.firstName + this.lastName
}
}
以物件的設計來理解,computed 是一種 getter 並且只能讀。
所以,在概念上,computed 屬於一種無法修改的回傳值。
不過實際上,它是一個被快取起來的值,所以依然存在著修改它的可能性,但是這是千千萬萬不要做的事情。要小心。
原本
<div><input type="text" v-model="user.firstName"></input></div>
可以改成讓 v-model
裡的文字變少的寫法。
<div><input type="text" v-model="firstName"></input></div>
整體的程式碼如下面這樣
<template>
<div>
<div><input type="text" v-model="firstName"></input></div>
<div><input type="text" v-model="lastName"></input></div>
<div>{{ fullName }}</div>
</div>
</template>
export default {
name: 'demo',
data() {
return {
user: {
firstName: 'Foo',
lastName: 'Bar',
},
};
},
computed: {
firstName: {
set(firstName) {
this.user.firstName = firstName;
},
get() {
return this.user.firstName;
},
},
lastName: {
set(lastName) {
this.user.lastName = lastName;
},
get() {
return this.user.lastName;
},
},
}
}
https://vuex.vuejs.org/guide/forms.html#two-way-computed-property
照著文件介紹,可以把 computed 的 get/set 讓 v-model
綁著一個名字,並且將 vuex 存取的方式 mutation 的 commit 和 getters (的 getters) 放在 computed 的 get/set 裡面。
會照著文件的指示,明明只是綁兩個欄位而已,卻寫得很多程式碼。如下:
<template>
<div>
<div><input type="text" v-model="firstName"></input></div>
<div><input type="text" v-model="lastName"></input></div>
<div>{{ fullName }}</div>
</div>
</template>
export default {
name: 'demo',
computed: {
firstName: {
set(firstName) {
this.$store.commit('firstName', firstName)
},
get() {
return this.$store.getters.firstName;
},
},
lastName: {
set(lastName) {
this.$store.commit('lastName', lastName)
},
get() {
return this.$store.getters.lastName;
},
},
}
}
若在這時候使用 pure component 就會出現在 pure component 裡面直接改 props 這樣做是不對的,這個之後會另外寫一篇專門介紹
也有另外一派,覺得如果要寫這多,也許就要槙重考慮是不是不要把所有的資料放在 vuex 裡面,必要的再放。這樣對狀態管理上來說是一件麻煩的事情,因為你只要用方便的 vuex 就會需要很麻煩的寫一堆 code
所以,在這個時候,我有延續著我那大膽的猜想,衍生出來的想法「 v-model
不是這麼必要使用呢?」
這是我偏好的寫法,若把 v-model
解開,就可以不要靠 computed 的 get/set 串資料,直接把語法寫在 html 上面,省掉這些一對一欄位串接的寫法,允許 :value
和 @input
的寫法不一樣,可以擁有不少彈性
這樣一來,上述的兩個麻煩就不再是麻煩了。所以把資料放進 vuex 裡面不是麻煩事,也不會擔心 pure component 的資傳遞是不是光綁欄位就超級麻煩。
而且 script
就可以放進真正複雜的程式碼,一行搞定的,都放 html 裡面
在Components Basics — Vue.js中,除了前述的「v-model
可以拆開寫」之外,拆開寫還有提醒兩個要注意的事情。
$event
這個關鍵字<input type="text" @input="$event">
的 $event
要注意它是什麼樣的物件。如果是原生的 input 就可能是原生的 event 物件,如果是 UI component 套件提供的 input 像是 Bootstrap 的 <b-input>
就是 value 本身。<template>
<div>
<div><input
type="text"
:value="$store.getters.firstName"
@input="$store.commit('firstName', $event.target.value)"
></div>
<div><input
type="text"
:value="$store.getters.lastName"
@input="$store.commit('lastName', $event.target.value)"
></div>
<div>{{ fullName }}</div>
</div>
</template>
export default {
name: 'demo',
computed: {
fullName() {
return this.user.firstName + this.user.lastName;
},
}
}
萬一 @input
出現複雜的情況或非同步的情況。都可以再寫成 mehotd 處理。就會讓複雜的情況進入 script 處理。
在之後 debug 掃視程式碼,也比較快找到容易出錯的複雜程式碼。
這是第一步,讓我感受到不用 v-model
的好處。script
的 code 就變得,讓我感覺不會雜雜的,簡單程式碼不會出現在這。