好吧,突然發(fā)現(xiàn)學(xué)不完了,一下子,那就分開吧,由于時間太久,直接重新大致復(fù)習(xí)了一下
微信小程序自定義組件
微信小程序支持自定義組件
下方的目錄

其中,components為組件目錄,nodemodules為模塊目錄,pages為小程序的頁面目錄,utils為一些基礎(chǔ)功能的封裝。好比安裝的第三方百度統(tǒng)計功能在此。
總說
創(chuàng)建一個組件
一個組件包括json,wxml,wxss,js四個文件組成。
wxml文件如下
<view class="inner">
{{innerText}}
</view>
<slot></slot>
編寫js文件
// components/component.js
Component({
/**
* 組件的屬性列表
*/
properties: {
innerText: {
type: String,
value: 'hello world'
}
},
/**
* 組件的初始數(shù)據(jù)
*/
data: {
},
/**
* 組件的方法列表
*/
methods: {
}
})
完成對組件的初始化,包括設(shè)置屬性列表,初始化數(shù)據(jù),以及設(shè)置相關(guān)的方法。
使用自定義組件
需要在json文件中聲明。
{
"usingComponents": {
"component": "/components/component"
}
}
在page目錄下設(shè)置組件的聲明,
<view><component></component></view>
好啦,上方的是一個最簡單的自定義組件
組件模板和樣式
組件模板
組件模板中有一個
<slot>
用于承載組件引用的時候提供的子節(jié)點。
ps 在page中引用的組件,必須在json文件中進行聲明。否則為無效節(jié)點
在wxml文件中
<view>
<component>
<text>這是文字</text>
</component>
</view>
而模板文件如下
<view class="inner">
{{innerText}}
</view>
<slot></slot>
這樣在page中的text節(jié)點會加載在slot節(jié)點的位置中。
使用多個slot
如果要使用多個slot需要在js文件中聲明
options: {
multipleSlots: true // 允許組件中使用多個slot
}
然后在組件的wxml文件中設(shè)置slot的內(nèi)容
<view class="inner">
<slot name="before"></slot>
{{innerText}}
<text>這是組件的內(nèi)部內(nèi)容</text>
<slot name="after"></slot>
</view>
使用slot的name屬性確定組件的內(nèi)容
在page頁面中,使用該組件
<view>
<component>
<text slot="before">這是文字</text>
<text slot="after">hello world</text>
</component>
</view>
組件樣式
對于組件樣式來說,使用
:host
來指定組件的默認(rèn)樣式。
即可指定默認(rèn)樣式
外部樣式類
使用外部傳入的屬性,在component中使用,即使用page中的wxss。
直接在component構(gòu)造函數(shù)中externalClasses屬性中,使用數(shù)組。
在同一個節(jié)點上使用普通樣式和外部樣式,兩個權(quán)重是相同的,會造成不可思議的bug產(chǎn)生。
在組件中,使用components構(gòu)造函數(shù)的externalClasses屬性確定外部樣式表的名稱
externalClasses: ['my-class']
然后在組件的wxml文件中,使用該外部樣式表
<view class="my-class">
<slot name="before"></slot>
{{innerText}}
<text>這是組件的內(nèi)部內(nèi)容</text>
<slot name="after"></slot>
</view>
然后,在page中使用
<view>
<component class="my-class">
<text slot="before">這是文字</text>
<text slot="after">hello world</text>
</component>
</view>
是滴,直接使用page中的樣式表,page中的樣式表
.my-class {
color:yellow
}
全局樣式表
使用全局樣式表設(shè)置js文件中的options對象中的addGlobalClass屬性為true可以使用全局樣式表
component構(gòu)造器
使用component構(gòu)造器,進行構(gòu)造。
該構(gòu)造函數(shù)用于定義組件。調(diào)用Component函數(shù)能指定組件的數(shù)據(jù),屬性和方法。
這個和視圖層的page構(gòu)造函數(shù)很類似。
在properties定義段中,屬性名采用駝峰命名法,wxml采用連字符的命名,之間相互轉(zhuǎn)換。
tips 在網(wǎng)頁中,也有這一點。
定義組件的js
Component({
behaviors: [], // 進行代碼復(fù)用機制
properties: {
myProperty: { // 屬性名
type: String, // 屬性的類型(必填)
value: '', // 屬性的初值
observer: (newValue, oldValue, changedPath) => {
console.log(newValue);
console.log(oldValue)
}
},
myProperty2: String // 一種簡化的定義方式
},
data: {}, // 私有數(shù)據(jù),用于模板渲染
lifetimes: {
// 組件的生命周期函數(shù),用于聲明組件的生命周期
attached: () => {},
moved: () => {},
detached: () => {}
},
pageLifetimes: {
// 組件所在頁面的生命周期函數(shù)
show: () => {},
hide: () => {}
},
methods: {
// 組件的方法,其中下劃線開頭為私有方法
onMyButtonTap: function() {
this.setData({
myProperty: "hello world"
})
},
// 內(nèi)部方法,使用下劃線開頭
_myPrivateMethod: function() {
this.setData({
'A[0].B': 'myPrivateData'
})
}
}
})
定義組件的wxml
<custom-component>
<view>{{myProperty}}</view>
<button bindtap='onMyButtonTap'>Button</button>
<view>{{A[0].B}}</view>
<button bindtap='_myPrivateMethod'>_myPrivateMethod</button>
</custom-component>
然后在page中使用該組件
在這之前json中設(shè)置該組件
<my-component />
接著運行如下

使用Component構(gòu)造函數(shù)構(gòu)造頁面
小程序的頁面可以視為自定義組件,因此,頁面同樣可以使用Component構(gòu)造函數(shù)構(gòu)造,此時要求對應(yīng)的json文件擁有usingComponents定義段
此時組件的屬性可以用于接收頁面的參數(shù),
在app.json文件中添加一個頁面,并在導(dǎo)航欄設(shè)置該頁面
{
"pages":[
"pages/helloWorld/hello",
"pages/index/index",
"pages/logs/logs",
"components/component"
],
"window":{
"backgroundTextStyle":"dark",
"navigationBarBackgroundColor": "#c7dbc8",
"navigationBarTitleText": "小小",
"navigationBarTextStyle":"whiter",
"enablePullDownRefresh": true,
"backgroundColor": "#fceaea"
},
"tabBar": {
"list": [{
"text": "ming",
"pagePath": "pages/logs/logs"
}, {
"text":"home",
"pagePath": "pages/index/index"
}, {
"text": "hello",
"pagePath": "pages/helloWorld/hello"
}, {
"text": "ing",
"pagePath": "components/component"
}],
"color": "#f8fcea",
"backgroundColor": "#ff9999",
"selectedColor": "#c5ff99",
"borderStyle": "white",
"position": "top"
},
"functionalPages": true
}
添加的參數(shù)為pages參數(shù),以及tabBar參數(shù)
并設(shè)置編譯模式,設(shè)置頁面的啟動參數(shù)
組件的js文件如下
// components/component.js
Component({
/**
* 組件配置
**/
options: {
multipleSlots: true // 允許組件中使用多個slot
},
/**
* 組件的屬性列表
*/
properties: {
innerText: {
type: String,
value: 'hello world'
},
paramA: Number,
paramB: Number,
},
/**
* 組件的初始數(shù)據(jù)
*/
data: {
},
/**
* 組件的方法列表
*/
methods: {
onLoad: function() {
console.log(this.data.paramA);
console.log(this.data.paramB);
}
},
/**
* 使用外部樣式表
**/
externalClasses: ['my-class']
})
添加了一個properties,并添加一個methods事件,在頁面加載的時候,觸發(fā)該事件。
啟動編譯,控制臺輸出當(dāng)前頁面參數(shù),參數(shù)獲取完成。
組件間通信和事件
通信的幾種方法
WXML數(shù)據(jù)綁定,用于父組件,向子組件指定的屬性設(shè)置數(shù)據(jù)。此方法僅僅能設(shè)置JSON數(shù)據(jù)。
事件,用于子組件向父組件傳遞數(shù)據(jù),可以傳遞任意數(shù)據(jù)。
監(jiān)聽事件
用于監(jiān)聽子組件,如果子組件被觸發(fā),則父組件將會觸發(fā)該事件。
<view>
<component class="my-class" bindmyevent="onMyEvent">
<text slot="before">這是文字</text>
<text slot="after">hello world</text>
</component>
</view>
當(dāng)子組件觸發(fā)了myevent事件時候,將會調(diào)用onMyEvent方法。
onMyEvent: function(e) {
console.log(e.detail); // 自定義組件觸發(fā)的時候。提供的detail事件。將會返回當(dāng)前點擊的鼠標(biāo)坐標(biāo)
}
觸發(fā)事件
使用triggerEvent方法,完成對父組件事件的觸發(fā)
wxml中添加
<button bindtap="onTap">點擊按鈕</button>
然后在js中添加
onTap: function() {
var myEventDetail = {}; // 提供給事件的監(jiān)聽函數(shù)
var myEventOption = {}; // 觸發(fā)事件的選項
this.triggerEvent('myevent', myEventDetail, myEventOption)
},
確保該組件將會有myevent供父組件進行觸發(fā)
類似于網(wǎng)頁中的自定義組件
完成綁定以后,由于上一節(jié),父組件以及完成事件的監(jiān)聽,此時點擊組件內(nèi)的按鈕,將會完成父組件綁定的事件的觸發(fā)
由于冒泡和傳播的存在,父組件依舊可以通過冒泡和傳播來進行獲取
triggerEvent方法詳細(xì)解釋
有三個參數(shù),第一個參數(shù)為暴露給父節(jié)點的事件類型。第二個參數(shù)為向父組件傳遞的數(shù)據(jù),第三個參數(shù)為選項,傳入對象進去
向父組件傳遞數(shù)據(jù)
組件的js文件中
onTap: function() {
var myEventDetail = {
a:3,
b:4,
c:5
}; // 提供給事件的監(jiān)聽函數(shù)
var myEventOption = {}; // 觸發(fā)事件的選項
this.triggerEvent('myevent', myEventDetail, myEventOption)
},
將對象傳入第二個選項中
接收數(shù)據(jù),在父組件的e.detail中接收子傳給父的內(nèi)容
完成了數(shù)據(jù)從子傳遞到父
上上上節(jié)介紹了父傳遞到子的過程
第三個參數(shù)
bubbles
該選型確定的是是否冒泡
由于composed默認(rèn)為false則該事件只在主樹上觸發(fā),不會進入任何其他組件的內(nèi)部。
編寫兩個嵌套的組件
在components目錄下繼續(xù)新建一個目錄為body
原諒自己的命名技術(shù),component命名╮(╯▽╰)╭
配置頁面的json文件信息
{
"usingComponents": {
"component": "/components/component",
"body": "/components/body/body"
}
}
接著繼續(xù)配置
書寫頁面的wxml文件
<body>
<component/>
</body>
由于是在原有基礎(chǔ)上添加,繼續(xù)書寫body組件的內(nèi)容,確定掛載點
<view>
<slot/>
</view>
編譯一個最基本的組件嵌套完成。為body組件,嵌套一個component組件
接著進行事件的綁定
書寫內(nèi)層組件的bubbles,為允許進行冒泡
var myEventOption = {
bubbles: true
}; // 觸發(fā)事件的選項
即完成允許冒泡。
接著,繼續(xù),書寫pages的wxml文件,完成事件和節(jié)點的綁定
<body bindmyevent="list2">
<component bindmyevent="list1"/>
</body>
接著單擊按鈕完成事件的觸發(fā)

至此,完成了事件的冒泡。
componse
確定事件是否進入內(nèi)部,即,是否觸發(fā)組件內(nèi)部
接著,在原來的代碼的基礎(chǔ)上繼續(xù)添加內(nèi)容。
由于內(nèi)部組件依舊是一個事件類型為myevent
接著,修改內(nèi)部組件的配置
onTap: function() {
var myEventDetail = {
a:3,
b:4,
c:5
}; // 提供給事件的監(jiān)聽函數(shù)
var myEventOption = {
bubbles: true,
composed: true
}; // 觸發(fā)事件的選項
this.triggerEvent('myevent', myEventDetail, myEventOption)
},
onMyEvent: function(e) {
console.log(e.detail); // 自定義組件觸發(fā)的時候。提供的detail事件。
}
修改composed的值為true。
綁定body的事件
<view bindmyevent="list3">
<slot/>
</view>
綁定body事件完成以后,接著單擊按鈕,觸發(fā)事件
觸發(fā)過程為1,3,2說明事件是先進入父組件,觸發(fā)父組件的事件完成以后,在繼續(xù)觸發(fā)引用組件的節(jié)點樹上的事件。
capturePhase
為事件是否有捕獲階段。
由于事件是先冒泡,后捕獲,所以必須要先進行冒泡
修改配置如下
var myEventOption = {
bubbles: false,
composed: true,
capturePhase: true
}; // 觸發(fā)事件的選項
然后觸發(fā)事件,由于是捕獲,將會觸發(fā)回調(diào)myevent的list1的回調(diào)函數(shù)進行處理。
behaviors
一種代碼復(fù)用機制
類似于C++的模板 ?? 確定嗎? 木有學(xué)習(xí)過c++,其實我一直在思考css文件如何實現(xiàn)復(fù)用。因為我不想寫大段代碼呀,(@ο@) 哇~
每個behavior都會包含一組屬性,數(shù)據(jù),生命周期函數(shù)和方法。組件引用的時候,上述將會合并
類似于深拷貝,不過js中的深拷貝是直接開辟了一塊新的儲存空間,淺拷貝屬于直接進行引用,js進行賦值操作執(zhí)行的是淺拷貝
使用Behavior()構(gòu)造函數(shù),進行構(gòu)造出代碼的復(fù)用
文件目錄如下

微信的路徑太坑了。
模板文件如下
module.exports = Behavior({
behaviors: [],
properties: { // 外部數(shù)據(jù)
myBehaviorProperty: {
type: String,
value: 'hello world'
}
}
})
屬于配置項目,接著繼續(xù)書寫內(nèi)部組件
// components/component.js
var myBehavior = require('/behaviors/behavior')
Component({
// 代碼復(fù)用
behaviors: [myBehavior],
/**
* 組件配置
**/
options: {
multipleSlots: false // 允許組件中使用多個slot
},
/**
* 組件的屬性列表
*/
properties: {
innerText: {
type: String,
value: 'hello world'
},
paramA: Number,
paramB: Number,
},
/**
* 組件的初始數(shù)據(jù)
*/
data: {
},
/**
* 組件的方法列表
*/
methods: {
onLoad: function() {
console.log(this.data.paramA);
console.log(this.data.paramB);
},
onTap: function() {
var myEventDetail = {
a:3,
b:4,
c:5
}; // 提供給事件的監(jiān)聽函數(shù)
var myEventOption = {
bubbles: false,
composed: true,
capturePhase: true
}; // 觸發(fā)事件的選項
this.triggerEvent('myevent', myEventDetail, myEventOption)
},
onMyEvent: function(e) {
console.log(e.detail); // 自定義組件觸發(fā)的時候。提供的detail事件。
}
},
/**
* 使用外部樣式表
**/
externalClasses: ['my-class']
})
在最上方引入文件,(微信小程序的路徑一個大坑),接著在behaviors引入即可??梢詁ehaviors引入behaviors即包的相互依賴。
構(gòu)建一個復(fù)雜的程序很有必要進行分包
內(nèi)置的behaviors
wx://form-field
使得自定義組件有類似表單控件的功能,將會在頁面觸發(fā)submit事件的時候?qū)苯痈綆峤?br>
演示
先創(chuàng)建一個組件
此時目錄結(jié)構(gòu)

好吧。是有一點復(fù)雜了
添加內(nèi)置組件,并設(shè)置data數(shù)據(jù)中的value的值
// components/custom-form-field/custom-form-field.js
Component({
/**
* 代碼復(fù)用 .讓其擁有表單屬性
**/
behaviors: ['wx://form-field'],
/**
* 組件的屬性列表
*/
properties: {
value: {
type: String,
value: "hello world"
}
},
/**
* 組件的初始數(shù)據(jù)
*/
data: {
},
/**
* 組件的方法列表
*/
methods: {
}
})
接著書寫page頁面中的內(nèi)容
引入組件
{
"usingComponents": {
"component": "/components/component",
"body": "/components/body/body",
"custom-form-field": "/components/custom-form-field/custom-form-field"
}
}
完后接著繼續(xù)書寫wxml中添加該表單組件,并添加提交按鈕
<form bindsubmit="formSubmit">
<custom-form-field name="custom-name">hello world</custom-form-field>
<button form-type="submit">提交</button>
</form>
添加事件的處理程序
formSubmit: function (e) {
console.log('form', e.detail.value)
console.log(333)
}
單擊按鈕,控制臺輸出鍵值對,到此完成。