微信小程序-快速完成一個(gè)自定義組件

與頁面(Page)相似,組件也由json膘融、wxml腊凶、wxss划咐、js四個(gè)文件組成。

與頁面不同的是钧萍,需要在組件對(duì)應(yīng)的json文件中作出如下聲明:

{
  "component": true
}

以表示當(dāng)前創(chuàng)建的是一個(gè)自定義組件褐缠。目前通過微信小程序開發(fā)者工具創(chuàng)建組件時(shí),json文件中會(huì)自動(dòng)生成這個(gè)定義风瘦,無需手動(dòng)處理队魏。

組件的簡(jiǎn)單定義

組件中wxmlwxss文件的編寫與普通頁面沒有不同。需要注意的是可以在wxss文件中使用:host選擇器來指定組件的默認(rèn)樣式万搔。

代碼示例如下:

<!--components/component-user.wxml-->
<view>
  <text>這是自定義組件User</text>
</view>
/* components/component-user.wxss */

/* 此處使用:host選擇器來指定組件的默認(rèn)樣式 */
:host {
  color: blue;
  font-style: italic;
}

組件的使用

如果需要在某個(gè)頁面中引用組件胡桨,則需要在這個(gè)頁面對(duì)應(yīng)的json文件中對(duì)需要使用的組件進(jìn)行聲明。此處以index頁面為例:
index.json文件中聲明要引用的組件:

{
  "usingComponents": {
    "user": "/components/component-user"
  }
}

user是為組件聲明的別名瞬雹,作為在index.wxml中引用組件的標(biāo)簽名昧谊。
index.wxml中引用組件:

<!-- index.wxml -->
<view>
  <text>index.wxml</text>
  <user />
</view>

效果如下:

組件模板

插入單個(gè)節(jié)點(diǎn)

如果要在自定義組件中特定位置插入一個(gè)節(jié)點(diǎn),則此時(shí)需要使用組件模板酗捌。
模板定義如下:

<!--components/component-user.wxml-->
<view>
  <text>這是自定義組件User</text>
  <!-- 使用slot標(biāo)簽作為插入view的節(jié)點(diǎn) -->
  <slot />
</view>

index.wxml中引用如下:

<!-- index.wxml -->
<view class="container">
  <text>index.wxml</text>

  <user>
    <!-- 這個(gè)view節(jié)點(diǎn)會(huì)插入到slot標(biāo)簽處作為自定義組件的一個(gè)節(jié)點(diǎn) -->
    <view style="color:#F78AE0">這個(gè)view會(huì)被插入到自定義組件的slot標(biāo)簽處</view>
  </user>
</view>

效果如下:


注意:可以在同一個(gè)slot標(biāo)簽處插入多個(gè)節(jié)點(diǎn)呢诬。

向特定位置插入節(jié)點(diǎn)

自定義組件默認(rèn)僅支持向slot處插入節(jié)點(diǎn)。如果想在一個(gè)自定義組件的特定位置插入節(jié)點(diǎn)的話胖缤,首先需要在js文件開啟支持多個(gè)slot的聲明尚镰。

// components/component-user.js
Component({
  options: {
    // 支持多個(gè)slot
    multipleSlots: true
  }
})

并且在wxml文件中為slot命名:

<!--components/component-user.wxml-->
<view>
  <text>這是自定義組件User</text>
  <!-- 使用slot標(biāo)簽作為插入view的節(jié)點(diǎn) -->
  <slot name="another-slot" />
  <view style='width:100%;height:1px;background:black' />
  <slot name="slot" />
</view>

然后在index.wxml中使用通過指定slot的名字來指定插入的位置:

<!-- index.wxml -->
<view class="container">
  <text>index.wxml</text>

  <user>
    <!-- 這個(gè)view節(jié)點(diǎn)會(huì)插入到slot標(biāo)簽處作為自定義組件的一個(gè)節(jié)點(diǎn) -->
    <view style="color:#F78AE0" slot="slot">這個(gè)view會(huì)被插入到slot處</view>
    <view style="color:#6638F0" slot="another-slot">這個(gè)view會(huì)被插入到another-slot處</view>
  </user>
</view>

效果如下:


注意:在開啟了多slot支持后,如果在組件中存在沒有命名的slot哪廓,并且index.wxml中也有未指定插入位置的節(jié)點(diǎn)狗唉,則默認(rèn)插入無名稱的slot處。

事件綁定

在使用模板時(shí)撩独,如果要為綁定的節(jié)點(diǎn)綁定事件敞曹,則添加在模板內(nèi)和引用處都可以,具體可以根據(jù)業(yè)務(wù)需求來區(qū)分综膀。
比如引用自定義組件的多處業(yè)務(wù)邏輯完全相同澳迫,則可以將事件綁定在模板中,減少重復(fù)代碼剧劝。如果引用自定義組件處業(yè)務(wù)有所不同橄登,則可以在引用處進(jìn)行事件綁定。
在模板中綁定事件時(shí),wxml文件中代碼與普通頁面中的代碼相同拢锹,區(qū)別在于js文件中方法的定義:

<!--components/component-user.wxml-->
<view>
  <text>這是自定義組件User</text>
  <!-- 使用slot標(biāo)簽作為插入view的節(jié)點(diǎn) -->
  <slot name="another-slot" />
  <view style='width:100%;height:1px;background:black' />
  <slot name="slot" catchtap="onSlotClick" />
</view>
// components/component-user.js
Component({
  options: {
    // 支持多個(gè)slot
    multipleSlots: true
  },
  /**
   * 組件的方法列表
   */
  methods: {
    onSlotClick: function(event) {
      console.log("onSlotClick in component-user.js")
    }
  }
})

在組件模板中綁定事件時(shí)谣妻,需要將事件的監(jiān)聽方法定義在methods中。

事件的冒泡順序

在使用事件模板時(shí)其實(shí)可以在模板wxml文件和頁面wxml文件中都對(duì)同一個(gè)節(jié)點(diǎn)進(jìn)行綁定卒稳,此時(shí)事件的冒泡順序可能會(huì)讓一部分人感到困擾蹋半。
index頁面中綁定事件代碼如下:

<!-- index.wxml -->
<view class="container">
  <text>index.wxml</text>

  <user>
    <!-- 這個(gè)view節(jié)點(diǎn)會(huì)插入到slot標(biāo)簽處作為自定義組件的一個(gè)節(jié)點(diǎn) -->
    <view style="color:#F78AE0" slot="slot" bindtap="onSlotClick">這個(gè)view會(huì)被插入到slot處</view>
    <view style="color:#6638F0" slot="another-slot">這個(gè)view會(huì)被插入到another-slot處</view>
  </user>
</view>
Page({
  onSlotClick: function(event) {
    console.log("onSlotClick in index.js")
  }
})

此時(shí)點(diǎn)擊slot,輸出如下:


有的同學(xué)會(huì)認(rèn)為component-user中的事件先響應(yīng)而index中的事件后充坑。
其實(shí)這是種錯(cuò)誤的認(rèn)知减江。這些同學(xué)錯(cuò)誤的將index.wxml中的節(jié)點(diǎn)當(dāng)做了component-user.wxml的外層節(jié)點(diǎn),而實(shí)際上index.wxml中定義的節(jié)點(diǎn)是要插入到component.user.wxml中的捻爷,實(shí)際為component-user.wxml中的子節(jié)點(diǎn)辈灼。

綁定數(shù)據(jù)

為自定義組件綁定數(shù)據(jù)和為模板綁定數(shù)據(jù)差別不大。區(qū)別在于為模板綁定數(shù)據(jù)時(shí)需要使用屬性data-<data-set-name>也榄,而為自定義組件綁定數(shù)據(jù)需要預(yù)先定義要綁定數(shù)據(jù)的屬性巡莹。
首先在component-user.js中定義要綁定事件的屬性:

// components/component-user.js
Component({
  options: {
    // 支持多個(gè)slot
    multipleSlots: true
  },
  /**
   * 組件的屬性列表
   */
  properties: {
    // 用于接收傳入的數(shù)據(jù)
    user: Object
  },

  /**
   * 組件的方法列表
   */
  methods: {
    onSlotClick: function(event) {
      console.log("onSlotClick in component-user.js")
    }
  }
})

component-user.js根據(jù)定義的屬性綁定數(shù)據(jù):

<!--components/component-user.wxml-->
<view>
  <text>這是自定義組件User</text>
  <!-- 使用slot標(biāo)簽作為插入view的節(jié)點(diǎn) -->
  <slot name="another-slot" />
  <view style='width:100%;height:1px;background:black' />
  <slot name="slot" catchtap="onSlotClick" />

  <view>name:{{user.name}}</view>
  <view>age:{{user.age}}</view>
  <view>gender:{{user.gender}}</view>
</view>

然后在引用組件的時(shí)候就可以使用user屬性來為組件傳遞數(shù)據(jù):

<!-- index.wxml -->
<view class="container">
  <text>index.wxml</text>
  <!-- 使用user屬性來向組件傳遞數(shù)據(jù) -->
  <user user="{{user}}">
    <!-- 這個(gè)view節(jié)點(diǎn)會(huì)插入到slot標(biāo)簽處作為自定義組件的一個(gè)節(jié)點(diǎn) -->
    <view style="color:#F78AE0" slot="slot" bindtap="onSlotClick">這個(gè)view會(huì)被插入到slot處</view>
    <view style="color:#6638F0" slot="another-slot">這個(gè)view會(huì)被插入到another-slot處</view>
  </user>
</view>
Page({
  onReady: function() {
    this.setData({
      user: {
        name: "自定義組件示例",
        age: "0",
        gender: "undetermined"
      }
    })
  },

  onSlotClick: function(event) {
    console.log("onSlotClick in component-user.js")
  }
})

顯示效果如下:

behaviors

behaviors用于在不同組件間進(jìn)行代碼共享。類似于Java中多個(gè)不同的類實(shí)現(xiàn)了相同的接口甜紫,則都具備了該接口的特性降宅。示例如下:
定義一個(gè)behavior

// component-behavior.js

module.exports = Behavior({
  properties: {
    userInBehavior: Object
  },
  methods: {
    onSlotClick: function(event) {
      console.log("onSlotClick called in component-behavior.js")
    }
  },
  lifetimes: {
    created() {
      console.log("created called in component-behavior.js")
    },
    attached() {
      console.log("attached called in component-behavior.js")
    },
    detached() {
      console.log("detached called in component-behavior.js")
    },
    ready() {
      console.log("ready called in component-behavior.js")
    }
  },
})

我們?cè)?code>component-behavior.js中定義了屬性userInBehavioronSlotClick方法棵介,并且添加了生命周期的回調(diào)钉鸯。

component-user.js也添加生命周期回調(diào),并且引入behavior

// components/component-user.js
var mBehavoir = require('component-behavior.js')

Component({
  options: {
    // 支持多個(gè)slot
    multipleSlots: true
  },
  // 此處引入定義的behavior
  behaviors: [mBehavoir],
  /**
   * 組件的屬性列表
   */
  properties: {
    // 用于接收傳入的數(shù)據(jù)
    user: Object
  },

  /**
   * 組件的初始數(shù)據(jù)
   */
  data: {

  },

  /**
   * 組件的方法列表
   */
  methods: {
    // 此處監(jiān)聽方法的定義與behavior中相同邮辽,behavior中的同名方法會(huì)被覆蓋
    onSlotClick: function(event) {
      console.log("onSlotClick in component-user.js")
    }
  },
  lifetimes: {
    created() {
      console.log("created called in component-user.js")
    },
    attached() {
      console.log("attached called in component-user.js")
    },
    detached() {
      console.log("detached called in component-user.js")
    },
    ready() {
      console.log("ready called in component-user.js")
    }
  }
})

component-user.wxml修改如下:

<!--components/component-user.wxml-->
<view>
  <text>這是自定義組件User</text>
  <!-- 使用slot標(biāo)簽作為插入view的節(jié)點(diǎn) -->
  <slot name="another-slot" />
  <view style='width:100%;height:1px;background:black' />
  <slot name="slot" catchtap="onSlotClick" />

  <view>name:{{user.name}}</view>
  <view>age:{{user.age}}</view>
  <view>gender:{{user.gender}}</view>
</view>

至此唠雕,behavior的定義和引入完成。運(yùn)行程序吨述,控制臺(tái)輸出如下:


我們發(fā)現(xiàn)component-behavior.jscomponent-user.js中的生命周期回調(diào)方法被依次調(diào)用岩睁。
在執(zhí)行點(diǎn)擊操作,結(jié)果如下:

我們發(fā)現(xiàn)component-behavior.js中的事件監(jiān)聽方法沒有執(zhí)行揣云。
component-user.js中的事件監(jiān)聽方法注釋掉再重試:

這次component-behavior.js中的事件監(jiān)聽方法被調(diào)用了捕儒。
總結(jié)一下:
behavior中定義的生命周期回調(diào)與組件模板中定義的生命周期回調(diào)不會(huì)互相覆蓋,而普通方法(例如事件監(jiān)聽方法為組件模板中的方法覆蓋behavior中的方法)邓夕。

我們還在component-behavior.js中定義了一個(gè)新的屬性userInBehavior刘莹,嘗試在index中傳遞數(shù)據(jù):

Page({
  onReady: function() {
    this.setData({
      user: {
        name: "自定義組件示例",
        age: "0",
        gender: "undetermined"
      },
      userInBehavior: {
        name: "name in behavior"
      }
    })
  },

  onSlotClick: function(event) {
    console.log("onSlotClick in index.js")
  }
})

index.wxml中綁定數(shù)據(jù):

<!-- index.wxml -->
<view class="container">
  <text>index.wxml</text>
  <!-- 使用user屬性來向組件傳遞數(shù)據(jù) -->
  <user user="{{user}}" userInBehavior="{{userInBehavior}}">
    <!-- 這個(gè)view節(jié)點(diǎn)會(huì)插入到slot標(biāo)簽處作為自定義組件的一個(gè)節(jié)點(diǎn) -->
    <view style="color:#F78AE0" slot="slot" bindtap="onSlotClick">這個(gè)view會(huì)被插入到slot處</view>
    <view style="color:#6638F0" slot="another-slot">這個(gè)view會(huì)被插入到another-slot處</view>
    
    <view style="color:red">這個(gè)節(jié)點(diǎn)使用了behavior中的數(shù)據(jù):name={{userInBehavior.name}}</view>
  </user>
</view>

為了讓未指定插入位置的節(jié)點(diǎn)能夠正常顯示,還需要在component-user.wxml中添加一個(gè)未命名的slot標(biāo)簽:

<!--components/component-user.wxml-->
<view>
  <text>這是自定義組件User</text>
  <!-- 使用slot標(biāo)簽作為插入view的節(jié)點(diǎn) -->
  <slot name="another-slot" />
  <view style='width:100%;height:1px;background:black' />
  <slot name="slot" catchtap="onSlotClick" />

  <view>name:{{user.name}}</view>
  <view>age:{{user.age}}</view>
  <view>gender:{{user.gender}}</view>

  <slot />
</view>

效果如下:


此處僅介紹了小程序自定義組件的簡(jiǎn)單使用焚刚,如果需要了解更復(fù)雜的特性点弯,請(qǐng)?jiān)L問官方文檔-自定義組件

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末矿咕,一起剝皮案震驚了整個(gè)濱河市抢肛,隨后出現(xiàn)的幾起案子狼钮,更是在濱河造成了極大的恐慌,老刑警劉巖捡絮,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件熬芜,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡福稳,警方通過查閱死者的電腦和手機(jī)涎拉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來灵寺,“玉大人曼库,你說我怎么就攤上這事区岗÷园澹” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵慈缔,是天一觀的道長(zhǎng)叮称。 經(jīng)常有香客問我,道長(zhǎng)藐鹤,這世上最難降的妖魔是什么瓤檐? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮娱节,結(jié)果婚禮上挠蛉,老公的妹妹穿的比我還像新娘。我一直安慰自己肄满,他們只是感情好谴古,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著稠歉,像睡著了一般掰担。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上怒炸,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天带饱,我揣著相機(jī)與錄音,去河邊找鬼阅羹。 笑死勺疼,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的捏鱼。 我是一名探鬼主播执庐,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼穷躁!你這毒婦竟也來了耕肩?” 一聲冷哼從身側(cè)響起因妇,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎猿诸,沒想到半個(gè)月后婚被,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡梳虽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年址芯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片窜觉。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谷炸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出禀挫,到底是詐尸還是另有隱情旬陡,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布语婴,位于F島的核電站描孟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏砰左。R本人自食惡果不足惜匿醒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望缠导。 院中可真熱鬧廉羔,春花似錦、人聲如沸僻造。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嫡意。三九已至举瑰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蔬螟,已是汗流浹背此迅。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留旧巾,地道東北人耸序。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鲁猩,于是被迫代替她去往敵國和親坎怪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349