微信小程序自定義組件

好吧幻赚,突然發(fā)現(xiàn)學(xué)不完了靶橱,一下子,那就分開吧营袜,由于時間太久撒顿,直接重新大致復(fù)習(xí)了一下

微信小程序自定義組件
微信小程序支持自定義組件
下方的目錄


image

其中,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é)點(diǎn)蓬衡。

ps 在page中引用的組件,必須在json文件中進(jìn)行聲明彤枢。否則為無效節(jié)點(diǎn)

在wxml文件中

<view>
<component>
  <text>這是文字</text>
</component>
</view>

而模板文件如下

<view class="inner">
  {{innerText}}
</view>
<slot></slot>

這樣在page中的text節(jié)點(diǎn)會加載在slot節(jié)點(diǎn)的位置中狰晚。

使用多個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é)點(diǎn)上使用普通樣式和外部樣式携取,兩個權(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)造器,進(jìn)行構(gòu)造尸昧。
該構(gòu)造函數(shù)用于定義組件揩页。調(diào)用Component函數(shù)能指定組件的數(shù)據(jù),屬性和方法烹俗。

這個和視圖層的page構(gòu)造函數(shù)很類似爆侣。

在properties定義段中,屬性名采用駝峰命名法幢妄,wxml采用連字符的命名兔仰,之間相互轉(zhuǎn)換。

tips 在網(wǎng)頁中蕉鸳,也有這一點(diǎn)乎赴。

定義組件的js

Component({
  behaviors: [], // 進(jìn)行代碼復(fù)用機(jī)制

  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 />

接著運(yùn)行如下


image

使用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)前點(diǎn)擊的鼠標(biāo)坐標(biāo)
    }

觸發(fā)事件

使用triggerEvent方法堂氯,完成對父組件事件的觸發(fā)
wxml中添加

<button bindtap="onTap">點(diǎn)擊按鈕</button>

然后在js中添加

onTap: function() {
      var myEventDetail = {}; // 提供給事件的監(jiān)聽函數(shù)
      var myEventOption = {}; // 觸發(fā)事件的選項
      this.triggerEvent('myevent', myEventDetail, myEventOption)
    },

確保該組件將會有myevent供父組件進(jìn)行觸發(fā)

類似于網(wǎng)頁中的自定義組件

完成綁定以后,由于上一節(jié)牌废,父組件以及完成事件的監(jiān)聽咽白,此時點(diǎn)擊組件內(nèi)的按鈕,將會完成父組件綁定的事件的觸發(fā)

由于冒泡和傳播的存在鸟缕,父組件依舊可以通過冒泡和傳播來進(jìn)行獲取

triggerEvent方法詳細(xì)解釋

有三個參數(shù)晶框,第一個參數(shù)為暴露給父節(jié)點(diǎn)的事件類型。第二個參數(shù)為向父組件傳遞的數(shù)據(jù)叁扫,第三個參數(shù)為選項三妈,傳入對象進(jìn)去

向父組件傳遞數(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ā)莫绣,不會進(jìn)入任何其他組件的內(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)容,確定掛載點(diǎn)

<view>
  <slot/>
</view>

編譯一個最基本的組件嵌套完成模燥。為body組件,嵌套一個component組件
接著進(jìn)行事件的綁定
書寫內(nèi)層組件的bubbles掩宜,為允許進(jìn)行冒泡

 var myEventOption = {
        bubbles: true
      }; // 觸發(fā)事件的選項

即完成允許冒泡蔫骂。
接著,繼續(xù)牺汤,書寫pages的wxml文件辽旋,完成事件和節(jié)點(diǎn)的綁定

<body bindmyevent="list2">
  <component bindmyevent="list1"/>
</body>

接著單擊按鈕完成事件的觸發(fā)


image

至此,完成了事件的冒泡。

componse

確定事件是否進(jìn)入內(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說明事件是先進(jìn)入父組件契沫,觸發(fā)父組件的事件完成以后,在繼續(xù)觸發(fā)引用組件的節(jié)點(diǎn)樹上的事件代芜。

capturePhase

為事件是否有捕獲階段埠褪。
由于事件是先冒泡,后捕獲挤庇,所以必須要先進(jìn)行冒泡
修改配置如下

      var myEventOption = {
        bubbles: false,
        composed: true,
        capturePhase: true
      }; // 觸發(fā)事件的選項

然后觸發(fā)事件钞速,由于是捕獲,將會觸發(fā)回調(diào)myevent的list1的回調(diào)函數(shù)進(jìn)行處理嫡秕。

behaviors

一種代碼復(fù)用機(jī)制

類似于C++的模板 渴语?? 確定嗎昆咽? 木有學(xué)習(xí)過c++驾凶,其實(shí)我一直在思考css文件如何實(shí)現(xiàn)復(fù)用。因?yàn)槲也幌雽懘蠖未a呀掷酗,(@ο@) 哇~

每個behavior都會包含一組屬性调违,數(shù)據(jù),生命周期函數(shù)和方法泻轰。組件引用的時候技肩,上述將會合并

類似于深拷貝,不過js中的深拷貝是直接開辟了一塊新的儲存空間浮声,淺拷貝屬于直接進(jìn)行引用虚婿,js進(jìn)行賦值操作執(zhí)行的是淺拷貝

使用Behavior()構(gòu)造函數(shù),進(jìn)行構(gòu)造出代碼的復(fù)用
文件目錄如下


image

微信的路徑太坑了泳挥。

模板文件如下

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引入即可⌒廖茫可以behaviors引入behaviors即包的相互依賴粤蝎。

構(gòu)建一個復(fù)雜的程序很有必要進(jìn)行分包

內(nèi)置的behaviors

wx://form-field

使得自定義組件有類似表單控件的功能,將會在頁面觸發(fā)submit事件的時候?qū)苯痈綆峤?br> 演示
先創(chuàng)建一個組件
此時目錄結(jié)構(gòu)


image

好吧袋马。是有一點(diǎn)復(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)
  }

單擊按鈕虑凛,控制臺輸出鍵值對,到此完成软啼。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末桑谍,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子祸挪,更是在濱河造成了極大的恐慌锣披,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贿条,死亡現(xiàn)場離奇詭異雹仿,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)整以,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進(jìn)店門胧辽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人公黑,你說我怎么就攤上這事邑商。” “怎么了凡蚜?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵人断,是天一觀的道長。 經(jīng)常有香客問我朝蜘,道長恶迈,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任芹务,我火速辦了婚禮蝉绷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘枣抱。我一直安慰自己熔吗,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布佳晶。 她就那樣靜靜地躺著桅狠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上中跌,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天咨堤,我揣著相機(jī)與錄音,去河邊找鬼漩符。 笑死一喘,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嗜暴。 我是一名探鬼主播凸克,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼闷沥!你這毒婦竟也來了萎战?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤舆逃,失蹤者是張志新(化名)和其女友劉穎蚂维,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體路狮,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡虫啥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了览祖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片孝鹊。...
    茶點(diǎn)故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖展蒂,靈堂內(nèi)的尸體忽然破棺而出又活,到底是詐尸還是另有隱情,我是刑警寧澤锰悼,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布柳骄,位于F島的核電站,受9級特大地震影響箕般,放射性物質(zhì)發(fā)生泄漏耐薯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一丝里、第九天 我趴在偏房一處隱蔽的房頂上張望曲初。 院中可真熱鬧,春花似錦杯聚、人聲如沸臼婆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽颁褂。三九已至故响,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間颁独,已是汗流浹背彩届。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留誓酒,地道東北人樟蠕。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像丰捷,于是被迫代替她去往敵國和親坯墨。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評論 2 361

推薦閱讀更多精彩內(nèi)容