在上一章節中,咱們將vue-cli
命令行工具生成的代碼骨架中的src目錄清理了一遍,而後從頭開始配置和編寫了一個能夠運行的小程序頁面,算是正真走上了使用mpvue開發小程序的第一步。今天咱們將進一步來了解和學習mpvue / Vue
的其餘重要功能。html
既然mpvue
是基於Vue的,那麼就沒有理由不進一步學習一下Vue最核心的東西:組件。組件系統是Vue應用開發中最具價值的特性之一,在前文中其實咱們就已經有在使用組件了,好比App.vue
和首頁index.vue
就是兩個Vue組件。vue
組件是一種抽象,容許咱們使用小型、獨立和一般可複用的組件構建大型應用。仔細想一想,幾乎任意類型的應用界面均可以抽象爲一個組件樹,若干的小組件能夠聚合成一個完整的界面:vue-cli
一個好的組件系統必定會有這些特色:封裝性、複用性、擴展性。對於Vue的組件來講,這幾點都算是實現的比較的優秀的。npm
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小程序開發,都會更加駕輕就熟、事半功倍的!