mpvue開發小程式教程(四)
- 2019 年 10 月 7 日
- 筆記
在上一章節中,我們將 vue-cli
命令行工具生成的程式碼骨架中的src目錄清理了一遍,然後從頭開始配置和編寫了一個可以運行的小程式頁面,算是正真走上了使用mpvue開發小程式的第一步。今天我們將進一步來了解和學習 mpvue/Vue
的其他重要功能。
既然 mpvue
是基於Vue的,那麼就沒有理由不進一步學習一下Vue最核心的東西:組件。組件系統是Vue應用開發中最具價值的特性之一,在前文中其實我們就已經有在使用組件了,比如 App.vue
和首頁 index.vue
就是兩個Vue組件。
組件是一種抽象,允許我們使用小型、獨立和通常可復用的組件構建大型應用。仔細想想,幾乎任意類型的應用介面都可以抽象為一個組件樹,若干的小組件可以聚合成一個完整的介面:

一個好的組件系統一定會有這些特點:封裝性、復用性、擴展性。對於Vue的組件來說,這幾點都算是實現的比較的優秀的。
組件的封裝性
Vue組件的寫法可以避免將屬於一個獨立邏輯單位的程式碼散落在各處,可以將介面(DOM)、樣式(CSS)、行為(JS)三部分的程式碼很好的組織在一起(推薦的實踐是使用 .vue
文件)。在設計編寫一個組件時,我們要記住的原則就是:
避免向外部暴露過多的東西,只暴露必要的外部交互介面(組件屬性、事件、方法等)。
下面我們來在原先的程式碼基礎上,創建一個簡單的按鈕點擊計數器組件,它將實現的功能是:點擊按鈕並展示已點擊按鈕次數、點擊清零按鈕實現點擊次數的歸零。在 src/components
目錄下,新建一個 click-counter.vue
組件文件,並編寫如下程式碼:
<template> <div class="click-counter"> <div class="counter-num">次數:{{num}}</div> <button class="counter-btn" @click="handleClick">點我呀!</button> <button class="counter-reset-btn" @click="handleResetClick">清零</button> </div></template> <script>export default { data() { return { num: 0 }; }, methods: { handleClick() { this.num += 1; }, handleResetClick() { this.num = 0; } }};</script> <style>.click-counter { display: flex; align-items: center; justify-content: center; border: 1px solid red; background-color: #ffffff; padding: 10px;} .counter-num,.counter-btn,.counter-reset-btn { flex: 1; margin: 3px;}</style>
編寫完這個組件後,我們來嘗試在首頁組件 src/pages/index/index.vue
文件中使用它:
<template> <div class="container" @click="clickHandle"> <div class="message">{{msg}}</div> <!-- 使用 click-counter 組件 --> <click-counter /> </div></template> <script>// 導入 click-counter 組件import ClickCounter from "@/components/click-counter"; export default { // 聲明在當前組件下使用 counter-click 組件 components: { ClickCounter }, data() { return { msg: "Hello" }; }, methods: { clickHandle() { this.msg = "Clicked!!!!!!"; } }};</script> <style scoped>.message { color: red; padding: 10px; text-align: center;}</style>
完成上面兩個步驟後,記得重新運行一下命令行 npm run dev
(注意點:新增文件必須重新運行該命令,編譯器不會自動檢測新加入的文件)。成功後通過微信開發者工具的模擬器查看,結果介面將會是這樣的:

點擊「點我呀!」按鈕,計數器就會累加點擊次數並更新介面上的數字;而點擊「清零」按鈕,則會將統計數字歸零。
回到程式碼上來看,對於 click-counter.vue
的使用者 index.vue
來說,它並不關心太多 click-counter.vue
的實現細節,引入該組件文件並進行聲明,就可以通過標籤的形式來使用它了,非常簡單明了。而且,這樣一個 click-counter.vue
組件也可以被拿到其他的Vue/mpvue程式碼中使用,其他使用者也並不需要關注它的實現細節,而只需要關心它能實現什麼功能就行了。這就是組件封裝帶來的好處。
不過,目前的這個click-counter組件還沒有跟它的父組件之間有什麼交互或通訊,沒有體現出「暴露介面」的特性,那讓我們來增加點程式碼,了解下這一特性。首先解釋一下我們要實現的功能:組件可以接收一個外部設置的初始點擊次數值,在點擊「點我呀!」按鈕的時候,從這個初始值開始進行累加;並且點擊按鈕後,可以通知組件的使用者(即父組件)當前的點擊統計值。
修改 click-counter.vue
的程式碼:
<template> <div class="click-counter"> <div class="counter-num">次數:{{num}}</div> <button class="counter-btn" @click="handleClick">點我呀!</button> <button class="counter-reset-btn" @click="handleResetClick">清零</button> </div></template> <script>export default { // 增加一個可從外部傳入的屬性initNum props: { initNum: { type: Number, default: 0 } }, data() { return { num: this.initNum //使用傳入的initNum值作為初始的點擊數 }; }, methods: { handleClick() { this.num += 1; this.notifyNum(); }, handleResetClick() { this.num = 0; this.notifyNum(); }, notifyNum() { //觸發自定義事件 clicknum this.$emit("clicknum", { num: this.num }); } }};</script> <style scoped>.click-counter { display: flex; align-items: center; justify-content: center; border: 1px solid red; background-color: #ffffff; padding: 10px;} .counter-num,.counter-btn,.counter-reset-btn { flex: 1; margin: 3px;}</style>
修改 index.vue
的程式碼:
<template> <div class="container" @click="clickHandle"> <div class="message">{{msg}}</div> <!-- 使用 click-counter 組件 --> <click-counter :init-num="10" @clicknum="handleClickNum" /> </div></template> <script>// 導入 click-counter 組件import ClickCounter from "@/components/click-counter"; export default { // 聲明在當前組件下使用 counter-click 組件 components: { ClickCounter }, data() { return { msg: "Hello" }; }, methods: { clickHandle() { this.msg = "Clicked!!!!!!"; }, handleClickNum(data) { console.log(">>>>>>", data.num); } }};</script> <style scoped>.message { color: red; padding: 10px; text-align: center;}</style>
觀察以上修改後的程式碼可以發現,在 click-couter.vue
中的主要變化是:
- 使用
props
定義了一個名為initNum
的數字型組件屬性(且初始值為0)。它可用於接收使用組件外部傳入的值。然後,這個initNum
值被賦值到data
中的屬性num
上作為它的初始值。 - 在兩個按鈕的click事件處理方法中,額外調用了一個
notifyNum()
方法,它向組件觸發了一個自定義事件clicknum
並攜帶了當前點擊次數值。
而在 index.vue
中的主要變化是實例化 click-counter
組件的這行程式碼:
<click-counter :init-num="10" @clicknum="handleClickNum" />
實例化組件的時候,為組件傳入了 initNum
屬性值 10
;並且添加了一個對自定義事件 clicknum
的監聽方法。
這樣一個結構實現了數據進入組件/數據傳出組件的機制,父子組件之間就能實現數據通訊。通過有限的通訊點進行數據互換,而不是直接進行函數調用,可以使得程式碼結構更優雅、更易維護。
組件的復用性
組件的復用性就好理解的多了,創建組件的目的,大多數時候就是希望這個組件可以被多個地方、多次使用,避免編寫重複的程式碼。比如我們前面的計數器組件,有可能一個項目中的多個頁面會用到,也可能一個頁面就會使用多次。
Vue組件的復用也是很容易的,比如我們要在前面例子中的 index.vue
中復用計數器組件,創建3個計數器,那麼直接在模板部分編寫3個標籤就行了:
<template> <div class="container" @click="clickHandle"> <div class="message">{{msg}}</div> <!-- 創建 3個 click-counter 組件 --> <click-counter :init-num="10" @clicknum="handleClickNum" /> <click-counter :init-num="20" @clicknum="handleClickNum" /> <click-counter :init-num="30" @clicknum="handleClickNum" /> </div></template>
運行後的效果如下圖所示,這三個計數器都能獨立統計各自的點擊數量:

組件的擴展性
談到擴展性,有面向對象編程經驗的開發者就會想到「繼承(extends)」。繼承是一種比較有效的擴展機制,不過隨著繼承的層次變深,程式碼也會變得難以理解。在Vue組件中,沒有採用繼承的機制,而是推薦使用「組合」的方式。
在組合理念下,我們盡量將想復用性高的組件設計到最小可拆分單位,比如按鈕、輸入框、單選框等等,然後再將這些低層組件放入更高層組件中,一層一層,慢慢拼裝出滿足需求的業務介面。
除了組合,Vue組件還提供了插槽(Slot)功能,相當於在一個組件中挖出了一個或多個坑,在具體使用這些具有插槽的組件時,可以選擇往坑裡面填什麼內容(其他組件)。
舉個例子,在計數器組件中,我們在清零按鈕後面用 <slot></slot>
挖了一個坑:
<template> <div class="click-counter"> <div class="counter-num">次數:{{num}}</div> <button class="counter-btn" @click="handleClick">點我呀!</button> <button class="counter-reset-btn" @click="handleResetClick">清零</button> <slot></slot> </div></template>
而後,在 index.vue
中使用計數器組件時,在 <click-counter>
標籤體中放入了額外的內容,會被傳入該組件中去用於填坑:
<template> <div class="container" @click="clickHandle"> <div class="message">{{msg}}</div> <!-- 使用 click-counter 組件 --> <click-counter :init-num="10" @clicknum="handleClickNum"> <!-- 填坑用... --> <input type="checkbox" /> 禁用 </click-counter> </div></template>
從運行結果可以看到,清零按鈕後面已經多出了我們傳入的複選框和文字內容:

插槽其實可以理解為是另一種形式的組件屬性:普通組件屬性傳入的是比較簡單類型的數據;而插槽傳入的可以是更複雜的介面組件而已。
小結
本文我們初步學習了一下Vue組件的相關理念和特性,希望大家花點時間去熟悉和掌握這些比較核心的知識點,相信不管在之後使用Vue進行Web應用開發,還是mpvue小程式開發,都會更加得心應手、事半功倍的!