自定義元件
小程式中內建了許多的元件供開發者使用,不僅如此開發者還可根據需要自定義元件。
基本語法
-
建立自定義元件
透過小程式開發者工具可以快速建立元件,新建Component。
建立好的自定義元件從結構上看與頁面是完全一致的,由 .wxml、.wxss、.js、.json 構成,也有兩點重要的區別:
- .json 檔案中必須有 component: true
- .js 檔案中呼叫的是 Component 函式
-
使用元件
元件需要在頁面或全域性中註冊後才可以使用,註冊元件會用到配置項
usingComponents
,它的值是物件型別資料,屬性名為自定義元件的名稱,屬性的值為自定義元件的路徑
全域性註冊
1、新增自定義元件,專案根目錄下新建components目錄,裡面在新建my-search目錄,在my-search目錄右鍵新建Component,輸入my-search,工具就會幫我們在my-search目錄下建立元件對應的四個檔案my-search.wxml、my-search.wxss、my-search.js、my-search.json
修改my-search.wxml中的內容
1 <text>我是自定義元件</text>
2、在app.json中註冊元件
1 { 2 "usingComponents": { 3 // key為註冊的元件名, value為元件路徑 4 "app-search": "/components/my-search/my-search" 5 }, 6 "entryPagePath": "pages/index/index", 7 "pages": [ 8 "pages/index/index", 9 "pages/logs/logs" 10 ], 11 12 "window": { 13 "navigationBarTextStyle": "black", 14 "navigationBarTitleText": "Weixin", 15 "navigationBarBackgroundColor": "#ffffff" 16 }, 17 "style": "v2", 18 "sitemapLocation": "sitemap.json" 19 }
3、在其他頁面這個全域性註冊的自定義元件
index.wxml
1 <app-search /> // 這裡就使用在app.json中註冊的自定義元件的名字
區域性註冊
在需要使用元件的頁面的xx.json檔案中新增如下內容,進行元件註冊
1 { 2 "usingComponents": { 3 "page-search": "/components/my-search/my-search" // key 為自定義的元件名稱(隨便起)使用的時候是按照這個名稱來使用的,value為元件的路徑 4 } 5 }
元件樣式
文件:https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html#%E7%BB%84%E4%BB%B6%E6%A0%B7%E5%BC%8F
在開發中經常會需要修改自定義元件內部的樣式,有兩種方式可以實現這個目的。- 樣式隔離:預設情況下頁面的樣式無法影響自定義元件的樣式
- 在元件的js檔案中,新增options: {addGlobalClass: true}, 來允許在頁面中修改自定義元件的樣式,但要求必須使用元件本身的類名
- 在元件中定義樣式時使用的選擇器不能是標籤選擇器、ID 選擇器或屬性選擇器
- 外部樣式類:
- externalClasses: ['xxx-class', 'yyy-class'] 開發自定義的樣式類
- xxx-class 和 yyy-class 可以接收外部傳入的類名,並應用到元件的佈局結構中
- 不要在元件內使用標籤選擇器、ID選擇器、屬性選擇器,會影響到全域性,這個不受樣式隔離限制
自定義導航欄元件
1、在專案根目錄新增components/my-nav目錄,然後在my-nav目錄右鍵新建Component,輸入my-nav元件名稱回車,會預設建立元件的四個檔案my-nav.wxml、my-nav.wxss、my-nav.js、my-nav.json
my-nav.wxml
1 <view class="navigation-bar custom-class"> 2 <view class="navigation-bar-title title-class"> 3 自定義標題 4 </view> 5 </view>
my-nav.wxss
1 /* components/my-nav/my-nav.wxss */ 2 .navigation-bar { 3 background-color: #ffffff; 4 height: 88rpx; 5 /* 頂部劉海預留 */ 6 padding: 100rpx; 7 display: flex; 8 justify-content: center; 9 } 10 11 .navigation-bar-title { 12 font-weight: bold; 13 }
2、在頁面使用
在專案根目錄新建pages/components,然後在components目錄右鍵新建Page,輸入index回車,會生成頁面的四個檔案index.wxml、index.wxss、index.js、index.json
index.js檔案中註冊元件,並設定使用自定義導航欄
1 { 2 "usingComponents": { 3 "page-nav": "/components/my-nav/my-nav" // 註冊自定義導航欄元件, key為元件註冊的名稱(在元件使用的時候,按照這個名稱使用),value為元件的路徑 4 }, 5 "navigationStyle": "custom" // 設定導航欄樣式自定義 6 }
index.wxml
1 <!--pages/component/index.wxml--> 2 <!-- 使用自定義導航欄的元件 --> 3 <page-nav />
3、檢視效果
4、此時元件my-nav在元件內部的樣式中設定了背景色為白色,但是想在頁面中動態的修改這個元件的顏色,在當前頁面的index.wxss檔案中透過類名navigation-bar來進行修改,發現是修改不了的,頁面和元件的樣式是隔離的
5、如果想在頁面修改使用的元件的樣式,
方式1:可以在元件的js檔案中新增如下配置 : options: {addGlobalClass: true}
1 // components/my-nav/my-nav.js 2 Component({ 3 options: { 4 addGlobalClass: true // 樣式預設隔離,為true則表示允許外部修改,一般都設定為true 5 }, 6 /** 7 * 元件的屬性列表 8 */ 9 properties: { 10 11 }, 12 13 /** 14 * 元件的初始資料 15 */ 16 data: { 17 18 }, 19 20 /** 21 * 元件的方法列表 22 */ 23 methods: { 24 25 } 26 })
6、此時在使用元件的頁面,透過元件的類名,來進行樣式的修改,就是可以的
1 /* pages/component/index.wxss */ 2 .navigation-bar { 3 background-color: gold; // 此時在頁面的樣式表中透過類名來修改元件的樣式 4 }
7、方式2:
在元件的js檔案中新增如下內容
1 // components/my-nav/my-nav.js // 元件的Js檔案 2 Component({ 3 // 方式1: 4 // options: {addGlobalClass: true}, // 樣式預設是隔離的,為true則表示允許外部修改 5 6 // 方式2:自定義樣式類 7 externalClasses: ['custom-class'], 8 /** 9 * 元件的屬性列表 10 */ 11 properties: { 12 13 }, 14 15 /** 16 * 元件的初始資料 17 */ 18 data: { 19 20 }, 21 22 /** 23 * 元件的方法列表 24 */ 25 methods: { 26 27 } 28 })
在頁面的樣式中定義樣式
1 /* pages/component/index.wxss */ 2 .color-pink { 3 color: pink; 4 }
使用元件的頁面index.wxml中使用元件並傳遞樣式類名
1 <!--pages/component/index.wxml--> 2 <!-- 使用自定義導航欄的元件 --> 3 <page-nav custom-class="color-pink"></page-nav>
8、檢視效果,可以看到傳遞的color-pink這個類名所帶的樣式,新增到元件身上的了
slot(插槽)
文件:https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html#%E7%BB%84%E4%BB%B6-wxml-%E7%9A%84-slot
小程式中預設只能使用一個 slot 需要多個插槽時需要傳入 options: { multipleSlots: true }。- 建立插槽:在元件的任意位置使用 <slot /> 進行佔位
- 預設只能使用 1 個 <slot>
- options: { multipleSlots: true } 啟用多插槽
- name 為不同的 <slot /> 命名來區分不同的插槽
- 使用插槽
- 單個插槽的情況下直接在元件中間填充內容即可
- 多外插槽的情況下需要使用
slot
屬性來指定插槽位置
單個插槽
在元件的內部,元件my-nav.wxml檔案中指定插槽的位置
1 <!--components/my-nav/my-nav.wxml--> 2 <view class="navigation-bar custom-class"> 3 <view class="navigation-bar-title title-class"> 4 <!-- 指定插槽的位置 --> 5 自定義標題 <slot></slot> 6 </view> 7 </view>
在頁面使用元件的時候,給插槽傳入內容
1 <!--pages/component/index.wxml--> 2 <!-- 使用自定義導航欄的元件 --> 3 <page-nav custom-class="color-pink"> 4 <!-- 向插槽傳內容 --> 5 <text>😄</text> <- 這就是傳到插槽的內容 整個text標籤 6 </page-nav>
多個插槽
1、啟用多插槽 元件js檔案新增配置:options: { multipleSlots: true }
my-nav.js
1 // components/my-nav/my-nav.js 2 Component({ 3 // 方式1: 4 // options: {addGlobalClass: true}, 5 6 // 方式2:自定義樣式類 7 externalClasses: ['custom-class'], 8 9 options: { 10 multipleSlots: true // 在元件定義時的選項中啟用多slot支援,一般都設定為true,用一個或者用多個都可以 11 }, 12 13 /** 14 * 元件的屬性列表 15 */ 16 properties: { 17 18 }, 19 20 /** 21 * 元件的初始資料 22 */ 23 data: { 24 25 }, 26 27 /** 28 * 元件的方法列表 29 */ 30 methods: { 31 32 } 33 })
2、給元件中的插槽新增name用於區分插槽位置
1 <!--components/my-nav/my-nav.wxml--> 2 <view class="navigation-bar custom-class"> 3 <view class="navigation-bar-title title-class"> 4 <!-- 指定多個插槽 --> 5 <slot name="left"></slot> 自定義標題 <slot name="right"></slot> 6 </view> 7 </view>
3、頁面中使用元件的時候,透過slot屬性指定插槽的名稱,從而將內容傳到指定的插槽位置
1 <!--pages/component/index.wxml--> 2 <!-- 使用自定義導航欄的元件 --> 3 <page-nav custom-class="color-pink"> 4 <!-- 向插槽傳內容 --> 5 <text slot="left">😄</text> 6 <text slot="right">☆</text> 7 </page-nav>
4、檢視效果
元件通訊
文件:https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/events.html
元件通訊是指將頁面或元件的資料傳入子元件內部或者將子元件的資料傳入父元件或頁面當中。
父傳子
自定義屬性:
元件透過自定義的屬性接收來自於元件外部(父元件或頁面)的資料
1、元件中定義要接收的屬性
1 // components/my-nav/my-nav.js 2 Component({ 3 options: { 4 // 方案1:addGlobalClass: true表示允許外部修改元件樣式 5 addGlobalClass: true, 6 multipleSlots: true // 在元件定義時的選項中啟用多slot支援 7 }, 8 // 方式2:自定義樣式類 9 externalClasses: ['custom-class'], 10 // 元件生命週期 11 lifetimes: { 12 // 相當於vue的created 13 // 14 created() { 15 // 幾乎不用,因為created()方法中使用this.setData()無效 16 }, 17 // 相當於vue的mounted 18 attached() { 19 // 獲取螢幕劉海的高度 20 const {statusBarHeight} = wx.getSystemInfoSync(); 21 console.log(statusBarHeight); 22 this.setData({ 23 statusBarHeight: statusBarHeight 24 }); 25 } 26 }, 27 /** 28 * 元件的屬性列表 - 父傳子(外部資料) 29 */ 30 properties: { 31 // 定義接收的屬性欄位,及型別 32 // back: Boolean // 只指定型別 33 34 // 指定型別並且設定預設值 35 back: { 36 type: Boolean, 37 value: true 38 }, 39 // 回退的層級 40 delta: { 41 type: Number, 42 value: 1 43 } 44 }, 45 46 /** 47 * 元件的初始資料 - (內部資料) 48 */ 49 data: { 50 statusBarHeight: 0 51 }, 52 53 /** 54 * 元件的方法列表 55 */ 56 methods: { 57 58 } 59 })
2、元件中使用這個屬性來判斷是否顯示返回
1 <!--components/my-nav/my-nav.wxml--> 2 <view class="navigation-bar custom-class" style="padding-top: {{ statusBarHeight }}px;"> 3 <view class="navigation-bar-title title-class"> 4 <!-- 使用父元件傳來的back,如果為true,則顯示該view,否則不顯示 --> 5 <!-- 使用navigator並且配合 open-type="navigateBack" 實現點選回退上一個頁面--> 6 <!-- 當navigator中open-type為"navigateBack"時,可以設定delta,指定返回的層級 --> 7 <navigator class="left" wx:if="{{ back }}" open-type="navigateBack" delta=" {{ delta }}">返回</navigator> 8 <slot name="right"></slot> 9 </view> 10 </view>
元件的樣式
1 /* components/my-nav/my-nav.wxss */ 2 .navigation-bar { 3 display: flex; 4 justify-content: center; 5 align-items: center; 6 position: relative; 7 } 8 9 .left { 10 position: absolute; 11 left: 20rpx; 12 }
3、頁面中註冊該導航元件,並且設定使用自定義導航,去掉預設的導航樣式
1 { 2 "usingComponents": { 3 "page-nav": "/components/my-nav/my-nav" // 註冊自定義導航元件 4 }, 5 "navigationStyle": "custom" 6 }
4、頁面中使用自定義導航元件,並且透過back屬性傳值,由於back為Boolean型別,所以透過插值表示式傳遞boolean型別的值,否則直接"aaa" 這是傳字串,這樣就導致back的值永遠為true
pages/test/index.wxml
1 <!-- 使用自定義導航欄的元件 --> 2 <page-nav custom-class="color-pink" back="{{ true }}"> 3 <text slot="right">☆</text> 4 </page-nav>
5、編譯小程式,可以看到當back傳true的時候頁面顯示返回字樣,當傳false的時候,沒有顯示返回
子傳父
自定義事件:
元件自定義事件的監聽:bind:事件型別(自定義)="事件回撥"
元件自定義事件的觸發:this.triggerEvent('事件型別(自定義)', 引數)
子元件繫結事件,在觸發該事件的時候,向父元件傳值
1 <!--components/my-nav/my-nav.wxml--> 2 <view class="navigation-bar custom-class" style="padding-top: {{ statusBarHeight }}px;"> 3 <view class="navigation-bar-title title-class"> 4 <!-- 使用父元件傳來的back,如果為true,則顯示該view,否則不顯示 --> 5 <!-- 使用navigator並且配合 open-type="navigateBack" 實現點選回退上一個頁面--> 6 <!-- 當navigator中open-type為"navigateBack"時,可以設定delta,指定返回的層級 --> 7 <navigator class="left" wx:if="{{ back }}" open-type="navigateBack" delta=" {{ delta }}">返回</navigator> 8 <!-- 給插槽繫結事件 --> 9 <slot bind:tap="onTap"></slot> 10 </view> 11 </view>
子元件js中定義事件,並且自定義觸發事件
1 // components/my-nav/my-nav.js 2 Component({ 3 options: { 4 // 方案1:addGlobalClass: true表示允許外部修改元件樣式 5 addGlobalClass: true, 6 multipleSlots: true // 在元件定義時的選項中啟用多slot支援 7 }, 8 // 方式2:自定義樣式類 9 externalClasses: ['custom-class'], 10 // 元件生命週期 11 lifetimes: { 12 // 相當於vue的created 13 // 14 created() { 15 // 幾乎不用,因為created()方法中使用this.setData()無效 16 }, 17 // 相當於vue的mounted 18 attached() { 19 // 獲取螢幕劉海的高度 20 const {statusBarHeight} = wx.getSystemInfoSync(); 21 console.log(statusBarHeight); 22 this.setData({ 23 statusBarHeight: statusBarHeight 24 }); 25 } 26 }, 27 /** 28 * 元件的屬性列表 - 父傳子(外部資料) 29 */ 30 properties: { 31 // 定義接收的屬性欄位,及型別 32 // back: Boolean // 只指定型別 33 34 // 指定型別並且設定預設值 35 back: { 36 type: Boolean, 37 value: true 38 }, 39 // 回退的層級 40 delta: { 41 type: Number, 42 value: 1 43 } 44 }, 45 46 /** 47 * 元件的初始資料 - (內部資料) 48 */ 49 data: { 50 statusBarHeight: 0 51 }, 52 53 /** 54 * 元件的方法列表 55 */ 56 methods: { 57 onTap() { 58 // 元件內部訪問資料 59 console.log("statusBarHeight: ", this.data.statusBarHeight) 60 // 將元件內部的資料傳遞給父元件 61 // this.triggerEvent("自定義事件名", 要傳遞的引數) 62 this.triggerEvent("getHeight", this.data.statusBarHeight) 63 } 64 } 65 })
頁面中使用子元件,並且監聽子元件自定義的事件
1 <!--pages/test/index.wxml--> 2 <!-- 使用自定義導航欄的元件 --> 3 <!-- bind:getHeight="getHeightFather" --> 4 <!-- bind:getHeight 繫結並監聽子元件自定義的事件,監聽到之後呼叫getHeightFather方法 --> 5 <page-nav custom-class="color-pink" back="{{ true }}" bind:getHeight="getHeightFather"> 6 <text>自定義導航</text> 7 </page-nav>
頁面(父元件)根據監聽到的事件,觸發對應的函式
1 // pages/test/index.js 2 Page({ 3 4 /** 5 * 頁面的初始資料 6 */ 7 data: { 8 9 }, 10 // 父元件的監聽事件 11 // 引數為事件物件 12 getHeightFather(e) { 13 console.log("獲取到的子元件傳遞的值為: ", e.detail) //e.detail就是傳遞的值 14 wx.showToast({ 15 icon: 'none', 16 title: `子元件狀態列高度為${e.detail}`, 17 }) 18 }, 19 /** 20 * 生命週期函式--監聽頁面載入 21 */ 22 onLoad(options) { 23 24 }, 25 26 /** 27 * 生命週期函式--監聽頁面初次渲染完成 28 */ 29 onReady() { 30 31 }, 32 33 /** 34 * 生命週期函式--監聽頁面顯示 35 */ 36 onShow() { 37 38 }, 39 40 /** 41 * 生命週期函式--監聽頁面隱藏 42 */ 43 onHide() { 44 45 }, 46 47 /** 48 * 生命週期函式--監聽頁面解除安裝 49 */ 50 onUnload() { 51 52 }, 53 54 /** 55 * 頁面相關事件處理函式--監聽使用者下拉動作 56 */ 57 onPullDownRefresh() { 58 59 }, 60 61 /** 62 * 頁面上拉觸底事件的處理函式 63 */ 64 onReachBottom() { 65 66 }, 67 68 /** 69 * 使用者點選右上角分享 70 */ 71 onShareAppMessage() { 72 73 } 74 })
Vant 元件庫
Vant 元件庫有 Vue 和小程式兩個版本,在使用時要注意區分!
Vant 元件庫小程式版
- npm 初始化
1 npm init
- 安裝,在小程式的根目錄中安裝
1 npm install @vant/weapp
-
修改
app.json
,移除全域性配置"style": "v2"
,否則 Vant 元件的樣式會受到影響 -
修改
project.config.json
,配置"setting"
選項中的packNpmManually
和packNpmRelationList
-
構建 npm,小程式中凡是透過 npm 下載的模組,都必須經過構建才能使用,構建後的程式碼會存放在 miniprogram_npm 中。
Vant 元件庫使用步驟請見 官方文件 - 快速上手