2024-11-11 vue computed

2024-11-11 vue computed

computed: {
formattedTime() {
為什麼 formattedTime()要寫在 computed?

為什麼 formattedTime() 要寫在 computed 中?

formattedTime() 放在 computed 中,是因為它的值是 從其他數據計算而來的,而且這個計算結果需要根據依賴的數據自動更新。以下是詳細解釋:


1. 自動依賴追蹤(核心原因)

  • formattedTime() 的結果依賴於 this.time
  • 如果 this.time 發生變化,computed 屬性會自動重新計算,無需手動更新。

例如:

1
this.time = 1000; // 當 this.time 變為 1000,formattedTime 自動更新

這比把 formattedTime 放在 data 中手動更新要高效且方便。


2. 避免重複計算

computed 屬性會緩存結果,只有當依賴數據發生變化時才重新計算。

  • 如果 formattedTime 是普通的函數,每次訪問都會重新執行(即使數據沒變化)。
  • computed 確保只有當 this.time 改變時才會重新執行,節省性能

3. 使模板簡潔

如果不使用 computed,需要在模板中直接計算:

1
<p>時間: {{ Math.floor(time / 60000) }}:{{ Math.floor((time % 60000) / 1000) }}</p>

這樣會讓模板變得冗長且難以閱讀。

computed

1
<p>時間: {{ formattedTime }}</p>

這樣模板會更加清晰直觀。


舉例比較:computed vs data

formattedTime 放在 data 中(需要手動更新):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
data() {
return {
time: 0,
formattedTime: "00:00:00",
};
},
methods: {
updateTime() {
this.time += 10;
const minutes = Math.floor(this.time / 60000);
const seconds = Math.floor((this.time % 60000) / 1000);
const milliseconds = Math.floor(this.time % 1000).toString().padStart(2, '0').slice(0, 2);
this.formattedTime = `${this.padZero(minutes)}:${this.padZero(seconds)}:${milliseconds}`;
}
}

這種做法的缺點:

  1. 需要手動計算並更新 formattedTime
  2. 容易漏掉更新邏輯,導致數據和顯示不同步。
  3. 增加代碼的複雜度。

使用 computed(自動更新):

1
2
3
4
5
6
7
8
9
10
11
12
13
data() {
return {
time: 0,
};
},
computed: {
formattedTime() {
const minutes = Math.floor(this.time / 60000);
const seconds = Math.floor((this.time % 60000) / 1000);
const milliseconds = Math.floor(this.time % 1000).toString().padStart(2, '0').slice(0, 2);
return `${this.padZero(minutes)}:${this.padZero(seconds)}:${milliseconds}`;
}
}

優點:

  1. this.time 改變時,formattedTime 自動重新計算。
  2. 確保數據和顯示同步,無需額外手動更新。
  3. 代碼簡潔,方便維護。

結論

computed 適合用於 依賴其他數據計算得來的屬性formattedTime() 是基於 this.time 計算得來的,因此放在 computed 中是最佳選擇。

為什麼是 this.time 改變時 就會執行 formattedTime?

為什麼 this.time 改變時會觸發 formattedTime

這是因為 Vue 的 響應式系統。Vue 會追蹤數據(例如 this.time)與 computed 屬性之間的依賴關係,當數據發生變化時,會自動重新計算依賴於這些數據的 computed 屬性。


詳細解釋

1. 響應式數據

this.time 是 Vue 中的響應式數據,當它的值改變時,Vue 會觸發與之相關的更新。

例如:

1
2
3
4
5
data() {
return {
time: 0 // time 是響應式的
};
}

2. 依賴追蹤

formattedTime 中,我們引用了 this.time

1
2
3
4
5
6
formattedTime() {
const minutes = Math.floor(this.time / 60000);
const seconds = Math.floor((this.time % 60000) / 1000);
const milliseconds = Math.floor(this.time % 1000).toString().padStart(2, '0').slice(0, 2);
return `${this.padZero(minutes)}:${this.padZero(seconds)}:${milliseconds}`;
}

formattedTime() 第一次執行時,Vue 的響應式系統會記錄它依賴了 this.time

3. 自動更新

this.time 改變時,Vue 會檢查哪些 computed 屬性依賴於 this.time,並自動重新計算這些屬性。例如:

1
this.time = 1000; // 修改響應式數據

這時,Vue 檢測到 formattedTime() 依賴於 this.time,就會自動重新執行 formattedTime(),以便更新最新的時間格式。


Vue 的響應式系統如何做到的?

  1. 數據代理
    當你定義了 data,Vue 會通過 Object.definePropertyProxy 將每個屬性轉為響應式的:

    • 當你讀取屬性(如 this.time)時,Vue 記錄依賴。
    • 當你修改屬性時,Vue 通知所有依賴於它的地方重新計算或更新。
  2. 依賴收集
    Vue 在計算 computed 屬性時,會動態追蹤哪些數據被訪問,並把這些數據和 computed 屬性關聯起來。

  3. 觸發更新
    當某個響應式數據(如 this.time)改變時,Vue 通知所有依賴它的 computed 屬性重新計算,並更新綁定的模板內容。


舉例:數據與 computed 的關係

假設你有以下代碼:

1
2
3
4
5
6
7
8
9
10
data() {
return {
time: 0
};
},
computed: {
formattedTime() {
return this.time * 2;
}
}

在模板中使用:

1
<p>{{ formattedTime }}</p>
  • this.time0 時,formattedTime 的結果是 0
  • 當你執行 this.time = 10 時:
    • Vue 檢測到 this.time 改變。
    • Vue 自動重新執行 formattedTime(),結果變為 20,並更新顯示的內容。

如果不用 computed,需要怎麼做?

如果你不用 computed,每次更新 this.time,都需要手動更新格式化的結果,例如:

1
2
3
4
5
6
7
8
9
10
11
12
data() {
return {
time: 0,
formattedTime: '00:00'
};
},
methods: {
updateTime() {
this.time += 10;
this.formattedTime = this.time * 2; // 手動更新
}
}

這樣做:

  1. 增加代碼的冗餘和複雜度。
  2. 容易出錯,例如忘記更新 formattedTime 時,UI 會顯示舊數據。

結論

當你把 formattedTime 放在 computed 中,Vue 幫你自動處理:

  1. 追蹤 this.timeformattedTime 的依賴關係。
  2. this.time 改變時,自動更新 formattedTime

這是 Vue 提供的響應式特性,讓代碼更加簡潔和高效。

computed 適合用於 依賴其他數據計算得來的屬性 ?

什麼是 computed

computed 是 Vue 中用來定義「計算屬性」的工具。這些屬性不是直接儲存在 data 裡,而是依賴於其他 data 或屬性計算得來的值。


「依賴其他數據計算得來的屬性」的意思

這表示 computed 屬性的值是根據其他響應式數據(例如 data 中的值)動態計算的。當這些響應式數據改變時,computed 屬性會自動重新計算,並更新顯示。


舉個例子

假設我們有一個網頁,讓使用者輸入名字和姓氏,並顯示全名。

1. 沒有使用 computed 的寫法

1
2
3
4
5
6
7
8
9
10
11
12
data() {
return {
firstName: 'John',
lastName: 'Doe',
fullName: '' // 手動存放全名
};
},
methods: {
updateFullName() {
this.fullName = this.firstName + ' ' + this.lastName; // 每次手動更新
}
}

每次 firstNamelastName 改變時,你必須手動呼叫 updateFullName() 更新 fullName

1
2
this.firstName = 'Jane';
this.updateFullName(); // 必須手動更新,否則 fullName 不會變

這樣會造成:

  1. 代碼冗長:每次數據改變都要手動更新。
  2. 容易出錯:如果忘記呼叫 updateFullName(),顯示的 fullName 就會是舊值。

2. 使用 computed 的寫法

1
2
3
4
5
6
7
8
9
10
11
data() {
return {
firstName: 'John',
lastName: 'Doe'
};
},
computed: {
fullName() {
return this.firstName + ' ' + this.lastName; // 自動計算全名
}
}

在模板中直接使用 fullName

1
<p>全名:{{ fullName }}</p>

當你修改 firstNamelastName 時,Vue 自動重新計算 fullName,無需手動更新:

1
2
this.firstName = 'Jane';
// 不需要手動更新,fullName 自動變為 'Jane Doe'

為什麼 computed 適合用於依賴其他數據計算的屬性?

  1. 自動更新:
    當依賴的數據(如 firstNamelastName)改變時,computed 屬性會自動重新計算,不需要額外的邏輯。

  2. 性能優化:
    computed 屬性有緩存機制,當依賴的數據沒有變化時,不會重新執行計算邏輯,節省資源。

  3. 代碼簡潔:
    你不需要手動撰寫更新邏輯(例如 updateFullName 方法),代碼更易於維護。


更多實例

例子 1:根據數據計算得來的值

1
2
3
4
5
6
7
8
9
10
11
data() {
return {
price: 100,
quantity: 2
};
},
computed: {
totalPrice() {
return this.price * this.quantity; // 自動計算總價
}
}

pricequantity 改變時,totalPrice 自動更新。


例子 2:格式化數據

1
2
3
4
5
6
7
8
9
10
11
12
data() {
return {
time: 1234567 // 毫秒
};
},
computed: {
formattedTime() {
const seconds = Math.floor(this.time / 1000) % 60;
const minutes = Math.floor(this.time / 60000);
return `${minutes}${seconds} 秒`;
}
}

time 改變時,formattedTime 自動以特定格式更新。


結論

computed 適合用於「依賴其他數據的屬性」,因為:

  1. 它能動態計算值,並且在依賴的數據改變時自動更新。
  2. 它有緩存機制,提升性能。
  3. 代碼簡潔易懂,不需要手動處理更新邏輯。

如果屬性不需要依賴其他數據,或者只需一次性初始化,那麼可以直接放在 data 中,而不是 computed