深入理解Vue 3:計算屬性與偵聽器的藝術

Amd794發表於2024-05-30

title: 深入理解Vue 3:計算屬性與偵聽器的藝術
date: 2024/5/30 下午3:53:47
updated: 2024/5/30 下午3:53:47
categories:

  • 前端開發

tags:

  • Vue3
  • 計算屬性
  • 偵聽器
  • 路由
  • 模板
  • 效能最佳化
  • 實戰案例

image

前言

Vue 3的新特性簡介

Vue.js作為當今流行的前端框架之一,以其響應式資料繫結和元件化架構著稱。隨著技術的不斷演進,Vue
3帶來了許多令人期待的新特性,這些特性不僅使得Vue.js更加高效和靈活,也為開發者提供了更好的開發體驗。

  1. Composition API:Vue 3引入了Composition API,它是對原有Options API的補充,使得程式碼更加模組化和可複用。透過組合式API,開發者可以更方便地組織和重用邏輯。
  2. Teleport:Teleport是一個新的內建元件,它允許開發者將子元件的內容移動到DOM的另一部分,而不改變它們的邏輯位置。這對於處理跨頁面或跨區域的互動非常有用。
  3. Suspense:Suspense是Vue 3中的另一個新特性,它允許元件在等待非同步元件或資料時渲染一個佔位符。這樣,開發者可以更優雅地處理非同步內容。
  4. Fragment:在Vue 2中,元件的模板必須有一個單一的根元素。Vue 3允許使用Fragment,即多個根元素,使得模板更加靈活。
  5. v-memo和v-model:v-memo是一個新的指令,用於快取計算屬性的結果,以提高效能。v-model則得到了改進,支援更多型別的輸入,如核取方塊和下拉選單。
  6. 更快的渲染速度:Vue 3透過最佳化虛擬DOM的演算法,提供了更快的渲染速度,使得應用更加流暢。

計算屬性與偵聽器的重要性

在Vue 3中,計算屬性(computed)和偵聽器(watch)是處理響應式資料和邏輯的兩個重要特性。它們在應用中起著至關重要的作用,使得資料處理更加高效和簡潔。

  1. 計算屬性:計算屬性是基於其他響應式資料的計算結果。它們具有快取特性,只有在依賴的資料發生變化時才會重新計算。這使得開發者能夠以宣告式的方式定義複雜的計算邏輯,而無需擔心不必要的計算。
  2. 偵聽器:偵聽器用於監聽響應式資料的變化。當資料發生變化時,偵聽器會執行回撥函式,從而允許開發者對資料的變化做出響應。偵聽器在處理非同步操作和複雜的資料依賴時尤為有用。

第一章:Vue 3基礎

1. Vue 3的安裝與配置

Vue 3可以透過CDN或NPM安裝。以下是使用NPM安裝Vue 3的步驟:

  1. 建立一個新的專案資料夾,並進入該資料夾。
mkdir my-vue-app
cd my-vue-app

  1. 初始化專案,並安裝Vue 3。
npm init -y
npm install vue@next

  1. 安裝完成後,可以在專案中使用Vue 3。
import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')

2. Vue 3的基本語法

Vue 3的基本語法與Vue 2類似,包括模板語法、資料繫結、條件渲染和迴圈渲染等。以下是一些基本語法的示例:

  • 資料繫結:
<template>
  <div>
    {{ message }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello Vue 3!'
    }
  }
}
</script>

  • 條件渲染:
<template>
  <div>
    <p v-if="show">顯示內容</p>
    <p v-else>隱藏內容</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      show: true
    }
  }
}
</script>

  • 迴圈渲染:
<template>
  <ul>
    <li v-for="item in items" :key="item.id">
      {{ item.name }}
    </li>
  </ul>
</template>

<script>
export default {
  data() {
    return {
      items: [
        { id: 1, name: 'Item 1' },
        { id: 2, name: 'Item 2' },
        { id: 3, name: 'Item 3' }
      ]
    }
  }
}
</script>

3. 元件與模板

元件是Vue 3最重要的構建塊,它允許開發者將應用分解為可重用的、獨立的部分。以下是建立和使用元件的基本步驟:

  • 建立元件:
// MyComponent.vue
<template>
  <div>
    <h1>{{ title }}</h1>
    <p>{{ content }}</p>
  </div>
</template>

<script>
export default {
  props: {
    title: {
      type: String,
      required: true
    },
    content: {
      type: String,
      required: true
    }
  }
}
</script>

  • 註冊元件:
import { createApp } from 'vue'
import App from './App.vue'
import MyComponent from './components/MyComponent.vue'

createApp(App).component('my-component', MyComponent).mount('#app')

  • 使用元件:
<template>
  <div>
    <my-component title="Hello" content="World"></my-component>
  </div>
</template>

元件可以接受Props,並透過事件和插槽進行通訊。元件還可以使用模板來定義其渲染結果,從而使得應用更加模組化和可重用。在Vue
3中,元件的建立和使用與Vue 2類似,但是有一些細節上的改動。本章將詳細介紹元件的建立、註冊和使用方法,以及如何使用Props、事件和插槽進行通訊。

第二章:計算屬性

1. 計算屬性的概念與作用

計算屬性(Computed
Properties)是Vue.js中一種特殊型別的響應式屬性,用於基於其他資料屬性的值來動態計算新的值。它們的主要作用是將資料處理邏輯從模板中分離出來,保持模板的簡潔,並確保效能最佳化,因為Vue會檢測依賴並僅在必要時重新計算。

2. 計算屬性的基本用法

計算屬性的定義通常在元件的datamethods物件中,但更推薦使用computed物件。例如:

export default {
  data() {
    return {
      a: 1,
      b: 2
    }
  },
  computed: {
    product() {
      return this.a * this.b;
    }
  }
}

在模板中,可以直接使用{{ product }}來顯示計算結果。

3. 計算屬性的高階用法

  • 多級計算:可以基於其他計算屬性來計算新的值。
computed: {
  product() {
    return this.a * this.b;
  },
  product3() {
    return this.product * this.c;
  }
}

  • 去除依賴:deep屬性可以用來控制是否深度檢測依賴,immediate屬性可以設定是否立即執行計算。
computed: {
  product3({ a, b, c }, { deep }) {
    return deep ? a * b * c : a * b + c;
  }
}

4. 快取機制

Vue的計算屬性有一個內部快取機制,如果計算結果沒有改變,Vue就不會再次執行計算函式。這對於計算密集型的屬性非常有用,避免了不必要的計算。

5. 依賴追蹤

Vue會自動追蹤計算屬性依賴的資料屬性變化,並在依賴變化時重新計算。這使得計算屬性總是反映出其依賴屬性的最新值。

6. 計算屬性的最佳實踐

  • 避免在計算屬性中執行昂貴的計算,儘可能在元件的methods中處理。
  • 儘量保持計算屬性的簡潔,只做必要的計算。
  • 使用deep屬性時要小心,因為它可能會導致不必要的重新渲染。

第三章:偵聽器

1. 偵聽器的概念與作用

偵聽器(Watcher)是Vue.js中的一個核心概念,它用於觀察和響應Vue例項上的資料變動。當被觀察的資料發生變化時,偵聽器會觸發相應的回撥函式,從而允許開發者執行響應的操作。偵聽器對於處理資料變化響應和執行副作用(例如資料載入、表單驗證等)非常有用。

2. 偵聽器的基本用法

在Vue中,可以透過watch選項來建立偵聽器。基本用法如下:

export default {
  data() {
    return {
      message: 'Hello, Vue!'
    }
  },
  watch: {
    message(newVal, oldVal) {
      console.log('Message changed from', oldVal, 'to', newVal);
    }
  }
}

在這個例子中,message屬性的任何變化都會觸發message偵聽器的回撥函式,該函式會接收到新值和舊值作為引數。

3. 偵聽器的高階用法

  • 配置選項:Vue的偵聽器提供了幾個配置選項,如deepimmediateflush,用於控制偵聽器的行為。
watch: {
  message(newVal, oldVal) {
    // ...
  },
  deep: true, // 深度偵聽
  immediate: true, // 立即執行
  flush: 'post' // 副作用在事件迴圈的“post”階段執行
}

  • 偵聽器物件:也可以向watch選項提供一個物件,其中包含了多個偵聽器配置:
watch: {
  // 監聽data中的message屬性
  message: {
    handler(newVal, oldVal) {
      // ...
    },
    deep: true,
    immediate: true
  },
  // 監聽data中的age屬性,但只在變化後執行
  age: {
    handler(newVal, oldVal) {
      // ...
    },
    immediate: false
  }
}

4. 深度偵聽

當偵聽一個物件或陣列時,預設情況下Vue只偵聽它們的頂級屬性變化。要啟用深度偵聽,需要在偵聽器的配置中設定deep: true

watch: {
  someObject: {
    handler(newVal, oldVal) {
      // ...
    },
    deep: true
  }
}

5. 立即執行的偵聽器

如果希望在元件掛載後立即執行偵聽器的回撥函式,可以在配置中設定immediate: true

watch: {
  someData: {
    handler(newVal, oldVal) {
      // ...
    },
    immediate: true
  }
}

6. 偵聽器的最佳實踐

  • 避免在偵聽器中進行復雜的計算或副作用,這可能會導致效能問題。
  • 儘量使用計算屬性而不是偵聽器來處理響應式資料的變化,因為計算屬性具有快取機制,可以更高效。
  • 只有在確實需要響應資料變化時才使用偵聽器,不要濫用。
    AD:漫畫首頁

第四章:計算屬性與偵聽器的對比

1. 計算屬性與偵聽器的異同

  • 計算屬性和偵聽器都是Vue.js中用於處理資料變化的工具,它們之間的主要區別在於使用場景和實現原理。
  • 計算屬性是一個返回值的函式,它依賴於其他資料來源,並且在資料變化時重新計算返回值。計算屬性具有快取機制,只有在依賴資料發生變化時才會重新計算。
  • 偵聽器是一個監聽資料變化並執行特定操作的函式,它可以配置深度偵聽和立即執行。

2. 何時使用計算屬性

  • 當需要從其他資料來源派生出一個新值時,可以使用計算屬性。
  • 當需要對資料進行格式化、過濾或排序時,可以使用計算屬性。
  • 當需要在模板中使用的資料是由其他資料計算而來時,可以使用計算屬性。

3. 何時使用偵聽器

  • 當需要在資料變化時執行特定操作,但不需要返回新值時,可以使用偵聽器。
  • 當需要監聽一個深度巢狀的物件或陣列時,可以使用偵聽器。
  • 當需要在資料變化後執行非同步操作或執行復雜計算時,可以使用偵聽器。

4. 結合使用計算屬性與偵聽器

  • 在某些情況下,可能需要使用計算屬性和偵聽器來實現更復雜的功能。例如,當需要在資料變化時執行特定操作,同時需要在模板中使用新計算出的值時,可以使用計算屬性和偵聽器結合。
  • 在這種情況下,可以在偵聽器中執行特定操作,同時在計算屬性中返回新值。

總結:計算屬性和偵聽器是Vue.js中處理資料變化的重要工具,它們之間的選擇取決於具體的使用場景。透過合理使用計算屬性和偵聽器,可以提高應用的響應性和靈活性。

第五章:實戰案例分析

案例一:購物車計算總價

為了實現一個簡單的購物車功能,我們需要按照以下步驟進行:

  1. 定義商品陣列

    • 建立一個陣列,用於儲存商品資訊。每個商品物件應包含名稱、價格和數量等屬性。
  2. 定義計算屬性

    • 建立一個計算屬性,用於計算購物車中所有商品的總價。這個計算屬性會遍歷商品陣列,將每個商品的價格乘以其數量,並將所有結果相加。
  3. 定義新增商品方法

    • 建立一個方法,用於向商品陣列中新增新的商品。這個方法需要接收商品的名稱、價格和數量作為引數,並建立一個新的商品物件新增到陣列中。
  4. 定義刪除商品方法

    • 建立一個方法,用於從商品陣列中刪除指定的商品。這個方法需要接收商品的名稱或索引作為引數,並從陣列中移除相應的商品物件。

下面是一個簡單的JavaScript示例程式碼,展示瞭如何實現上述功能:

// 定義商品陣列
let cart = [];

// 定義計算屬性
function calculateTotalPrice() {
    return cart.reduce((total, item) => total + (item.price * item.quantity), 0);
}

// 定義新增商品方法
function addToCart(name, price, quantity) {
    cart.push({ name, price, quantity });
}

// 定義刪除商品方法
function removeFromCart(name) {
    cart = cart.filter(item => item.name !== name);
}

// 使用示例
addToCart('Apple', 1.0, 5);
addToCart('Banana', 0.5, 10);
console.log('Total Price:', calculateTotalPrice()); // 輸出總價
removeFromCart('Apple');
console.log('Total Price after removing Apple:', calculateTotalPrice()); // 輸出移除蘋果後的總價

這段程式碼首先定義了一個空的商品陣列cart,然後定義了計算總價、新增商品和刪除商品的方法。透過呼叫這些方法,可以實現購物車的基本功能。

案例二:表單驗證與狀態偵聽

為了實現表單驗證和狀態偵聽的功能,我們可以使用Vue.js框架來展示這個案例,因為Vue.js提供了響應式資料和事件偵聽的機制。以下是一個簡單的Vue.js示例程式碼:

<template>
  <div>
    <input v-model="formData.inputValue" placeholder="請輸入內容">
    <button :disabled="!isValid">提交</button>
    <p v-if="formError">{{ formError }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      formData: {
        inputValue: '',
      },
      formError: null,
    };
  },
  computed: {
    isValid() {
      // 這裡可以新增更復雜的驗證邏輯
      return this.formData.inputValue.length >= 5; // 至少輸入5個字元才能提交
    }
  },
  methods: {
    submitForm() {
      if (this.isValid) {
        // 表單提交邏輯
        console.log('Form submitted with value:', this.formData.inputValue);
        // 提交成功後,可以清除錯誤資訊
        this.formError = null;
      } else {
        // 如果表單無效,顯示錯誤資訊
        this.formError = '輸入內容不能少於5個字元';
      }
    }
  },
  watch: {
    // 偵聽輸入框資料變化
    formData: {
      handler(newValue) {
        // 當formData發生變化時,執行某些操作
        if (newValue.inputValue.length < 5) {
          this.formError = '輸入內容不能少於5個字元';
        } else {
          this.formError = null;
        }
      },
      deep: true // 深度監聽
    }
  }
};
</script>

在這個示例中,我們使用了Vue.js的v-model來建立雙向資料繫結,這樣輸入框的內容就會實時更新到formData.inputValue
。我們定義了一個計算屬性isValid來判斷輸入是否有效,只有當輸入框的內容滿足條件時,按鈕才可用。

同時,我們新增了一個submitForm方法來處理表單提交,並且在表單驗證失敗時顯示錯誤資訊。我們還使用了一個watch
偵聽器來監聽formData的變化,這樣即使輸入框的內容是逐漸變化的,我們也能及時響應並更新按鈕狀態和錯誤資訊。
AD:專業搜尋引擎

這個案例展示了Vue.js在處理表單驗證和狀態偵聽方面的能力,透過響應式系統和事件機制,可以輕鬆實現動態表單處理。

案例三:動態路由與頁面渲染

為了實現動態路由和頁面渲染的功能,我們可以使用Vue Router,它是Vue.js官方的路由管理器。以下是一個簡單的Vue Router示例程式碼:

// 1. 定義路由陣列
const routes = [
  { path: '/home', component: Home },
  { path: '/about', component: About },
  { path: '/contact', component: Contact }
];

// 2. 建立Vue Router例項
const router = new VueRouter({
  routes // 將路由陣列傳遞給VueRouter
});

// 3. 定義動態路由匹配函式(這裡不需要,因為Vue Router會自動處理)

// 4. 定義鉤子函式,在路由切換時更新頁面標題
router.beforeEach((to, from, next) => {
  // 更新頁面標題
  document.title = to.meta.title || '預設標題';
  next();
});

// 在Vue例項中使用路由
new Vue({
  router,
  render: h => h(App)
}).$mount('#app');

在這個示例中,我們首先定義了一個路由陣列routes,其中包含了不同的路由路徑和對應的元件。然後,我們建立了一個Vue
Router例項,並將路由陣列傳遞給它。

Vue Router會自動處理動態路由匹配,因此我們不需要額外定義一個動態路由匹配函式。

為了在路由切換時更新頁面標題,我們使用了Vue Router的全域性前置守衛beforeEach。在這個鉤子函式中,我們根據當前路由物件to
meta屬性中的title來更新頁面標題。如果meta屬性中沒有定義title,則使用預設標題。

第六章:效能最佳化

計算屬性與偵聽器的效能考量

計算屬性

  • 計算屬性是基於它們的依賴進行快取的。只有在相關依賴發生改變時,它們才會重新計算。這意味著,如果一個計算屬性依賴的資料沒有變化,多次訪問該計算屬性將立即返回快取的結果,而不是重新執行計算邏輯。
  • 效能最佳化:確保計算屬性的依賴儘可能少,這樣可以減少不必要的計算。

偵聽器

  • 偵聽器(watch)用於觀察和響應Vue例項上的資料變動。當需要在資料變化時執行非同步或開銷較大的操作時,這是很有用的。
  • 效能最佳化:避免在偵聽器中執行復雜的計算或操作,因為偵聽器沒有快取機制,每次資料變化都會觸發偵聽器。

避免不必要的計算與偵聽

  • 避免在模板中進行復雜計算:模板應該保持簡潔,避免在模板中進行復雜的邏輯運算,這些應該放在計算屬性中。
  • 合理使用偵聽器:只在必要時使用偵聽器,例如,當需要在資料變化時執行非同步操作或開銷較大的操作時。
  • 使用computed代替watch:如果一個操作可以被快取,那麼應該優先使用計算屬性而不是偵聽器。

使用Vue Devtools進行效能分析

Vue Devtools是一個瀏覽器擴充套件,它允許開發者檢查Vue應用的狀態,包括元件樹、資料、事件和效能。

  • 效能皮膚:Vue Devtools提供了一個效能皮膚,可以用來分析元件的渲染時間和更新時間。
  • 時間線:透過時間線檢視,可以檢視應用在執行時的效能表現,包括元件的渲染和更新。
  • 元件檢查:可以檢查特定元件的效能,檢視其計算屬性和偵聽器的執行情況。

使用Vue Devtools進行效能分析的步驟通常包括:AD:首頁 | 一個覆蓋廣泛主題工具的高效線上平臺

  1. 安裝並啟用Vue Devtools擴充套件。
  2. 在瀏覽器中開啟Vue應用。
  3. 開啟Vue Devtools,切換到效能皮膚。
  4. 分析元件的渲染和更新效能,識別效能瓶頸。
  5. 根據分析結果最佳化程式碼,例如減少不必要的計算屬性或偵聽器。
    最後,我們將Vue Router例項注入到Vue應用中,並在根元件App中使用<router-view>來渲染匹配的元件。

這個案例展示瞭如何使用Vue Router來實現動態路由和頁面渲染,以及如何在路由切換時動態更新頁面標題。透過Vue
Router,我們可以輕鬆地管理複雜的應用路由,並提供流暢的使用者體驗。

第七章:常見問題與解決方案

計算屬性與偵聽器的常見錯誤

  1. 計算屬性錯誤

    • 忘記在計算屬性中使用return語句。
    • 計算屬性依賴的資料變化時,沒有重新計算。
    • 在計算屬性中更改響應式資料,導致檢視更新異常。
  2. 偵聽器錯誤

    • 偵聽器回撥函式中使用this時,this的上下文不正確。
    • 偵聽器沒有正確地設定deep屬性,導致深層次物件變化不被監聽。
    • 在偵聽器回撥中進行非同步操作時,可能忘記處理錯誤情況。

如何除錯計算屬性與偵聽器

  1. 計算屬性除錯

    • 使用瀏覽器的開發者工具,檢查計算屬性是否在預期的時候被重新計算。
    • 在計算屬性的getter函式中新增除錯日誌,檢視依賴資料變化時是否被正確更新。
    • 使用Vue Devtools監控計算屬性的快取情況。
  2. 偵聽器除錯

    • 同樣使用開發者工具的日誌功能,檢查偵聽器是否在資料變化時被觸發。
    • 在偵聽器的回撥函式中新增除錯日誌,確保非同步操作按預期執行。
    • Vue Devtools也可以幫助你監控和除錯偵聽器。

社群中的常見問題與解答

  1. 計算屬性與偵聽器的選擇

    • 社群中經常討論的問題是,何時應該使用計算屬性,何時應該使用偵聽器。
    • 一般建議是,如果資料變化需要同步計算,且結果需要被複用,使用計算屬性。如果資料變化需要執行非同步操作或深層次的資料監聽,使用偵聽器。
  2. 效能最佳化

    • 社群中關於效能最佳化的討論非常活躍,因為效能對於大型應用至關重要。
    • 常見的最佳化建議包括避免不必要的計算和偵聽,合理使用計算屬性和偵聽器,以及使用Vue Devtools進行效能分析。
  3. 複雜邏輯的處理

    • 在處理複雜邏輯時,社群通常建議將邏輯提取到方法中,而不是直接在模板或計算屬性中實現。
    • 對於需要多次讀取的結果,使用計算屬性;對於一次性讀取的結果,使用方法。

附錄

Vue 3官方文件參考

  • Vue 3官方文件:英文版
  • Vue 3官方文件(中文版):中文版翻譯
  • Vue 3官方文件(舊版中文版):舊版中文版

相關資源與社群連結

  • Vue.js GitHub
  • Vue.js 中文社群
  • Vue.js 論壇
  • Vue.js 示例和元件庫
  • Vue Devtools
  • Vite:Vue 3的構建工具,用於快速開發和構建Vue應用
  • Vue Router:Vue 3的官方路由管理器
  • Vuex:Vue 3的官方狀態管理庫

相關文章