支付寶小程序框架 自定義組件·模板和樣式

2020-09-18 10:31 更新

與頁面類似,自定義組件可以有自己的 axml 模板和 acss 樣式。

axml

axml 是自定義組件必選部分。

<!-- /components/index/index.axml -->
<view onTap="onMyClick" id="c-{{$id}}"/>
// /components/index/index.js
Component({
  methods: {
    onMyClick(e) {
      console.log(this.is, this.$id);
    },
  },
});

注意: 與頁面不同,用戶自定義事件需要放到 methods 里面。

插槽 slot

通過在組件 js 中支持 props,自定義組件可以和外部調用者交互,接受外部調用者傳來的數(shù)據(jù),同時可以調用外部調用者傳來的函數(shù),通知外部調用者組件內部的變化。

但是這樣還不夠,自定義組件還不夠靈活。除了數(shù)據(jù)的處理與通知,小程序提供的 slot 使得自定義組件的 axml 結構可以使用外部調用者傳來的 axml 組裝。

外部調用者可以傳遞 axml 給自定義組件,自定義組件使用其組裝出最終的組件 axml 結構。

默認插槽 default slot

示例代碼:

<!-- /components/index/index.axml -->
<view>
  <slot>
    <view>default slot & default value</view>
  </slot>
  <view>other</view>
</view>

調用者不傳遞 axml

// /pages/index/index.json
{
   "usingComponents": {
     "my-component": "/components/index/index"
   }
}
<!-- /pages/index/index.axml -->
<my-component />

頁面輸出:

default slot & default value
other

調用者傳遞 axml

<!-- /pages/index/index.axml -->
<my-component>
  <view>header</view>
  <view>footer</view>
</my-component>

頁面輸出:

header
footer
other

可以將 slot 理解為插槽,default slot 就是默認插槽,如果調用者在組件標簽 <my-component> 之間不傳遞 axml,則渲染的是默認插槽。而如果調用者在組件標簽 <my-component> 之間傳遞有 axml,則使用其替代默認插槽,進而組裝出最終的 axml 以供渲染。

具名插槽 named slot

default slot 只能傳遞一份 axml。

復雜的組件需要在不同位置渲染不同的 axml,即需要傳遞多個 axml,此時需要 named slot。 使用 named slot 后,外部調用者可以在自定義組件標簽的子標簽中指定要將哪一部分的 axml 放入到自定義組件的哪個具名插槽中,而自定義組件標簽的子標簽中沒有指定具名插槽的部分則會放入到默認插槽上。

如果僅僅傳遞了具名插槽,則默認插槽不會被覆蓋。

示例代碼:

<!-- /components/index/index.axml -->
<view>
  <slot>
    <view>default slot & default value</view>
  </slot>
  <slot name="header"/>
  <view>body</view>
  <slot name="footer"/>
</view>

只傳遞具名插槽

<!-- /pages/index/index.axml -->
<my-component>
  <view slot="header">header</view>
  <view slot="footer">footer</view>
</my-component>

頁面輸出:

default slot & default value
header
body
footer

傳遞具名插槽與默認插槽

<!-- /pages/index/index.axml -->
<my-component>
  <view>this is to default slot</view>
  <view slot="header">header</view>
  <view slot="footer">footer</view>
</my-component>

頁面輸出:

this is to default slot
header
body
footer

作用域插槽 slot-scope

通過使用 named slot ,自定義組件的 axml 要么使用自定義組件的 axml,要么使用外部調用者(比如頁面)的 axml。 使用自定義組件的 axml,可以訪問組件內部的數(shù)據(jù),同時通過 props 屬性,可以訪問外部調用者的數(shù)據(jù)。

示例代碼:

// /components/index/index.js
Component({
  data: {
    x: 1,
  },
  props: {
    y: '',
  },
});
<!-- /components/index/index.axml -->
<view>component data: {{x}}</view>
<view>page data: {{y}}</view>
// /pages/index/index.js
Page({
  data: { y: 2 },
});
<!-- /pages/index/index.axml -->
<my-component y="{{y}}" />

頁面輸出:

component data: 1
page data: 2

自定義組件通過 slot 使用外部調用者(比如頁面)的 axml 時,卻只能訪問外部調用者的數(shù)據(jù)。

示例代碼:

<!-- /components/index/index.axml -->
<view>
  <slot>
    <view>default slot & default value</view>
  </slot>
  <view>body</view>
</view>
// /pages/index/index.js
Page({
  data: { y: 2 },
});
<!-- /pages/index/index.axml -->
<my-component>
  <view>page data: {{y}}</view>
</my-component>

頁面輸出:

page data: 2
body

slot scope 使得插槽內容可以訪問到組件內部的數(shù)據(jù)。

示例代碼:

// /components/index/index.js
Component({
  data: {
    x: 1,
  },
});
<!-- /components/index/index.axml -->
<view>
  <slot x="{{x}}">
    <view>default slot & default value</view>
  </slot>
  <view>body</view>
</view>
// /pages/index/index.js
Page({
  data: { y: 2 },
});
<!-- /pages/index/index.axml -->
<my-component>
  <view slot-scope="props">
    <view>component data: {{props.x}}</view>
    <view>page data: {{y}}</view>
  </view>
</my-component>

頁面輸出:

component data: 1
page data: 2
body

如上所示,自定義組件通過定義 slot 屬性的方式暴露組件內部數(shù)據(jù),頁面使用組件時,通過 slot-scope 申明為作用域插槽,屬性值定義臨時變量名 props,即可訪問到組件內部數(shù)據(jù)。

acss

和頁面一樣,自定義組件也可以定義自己的 acss 樣式。acss 會自動被引入使用組件的頁面,不需要頁面手動引入。詳見 acss 語法。

使用示例

下面我們通過一個示例詳細看下 component2 的使用,具體代碼參見: https://github.com/ant-mini-program/component2-demo

// /pages/complex/complex.js
Page({
  data:{
    count: 2
  },
  plus() {
    this.setData({
      count: this.data.count + 1,
    })
  },
});
<!-- /pages/complex/complex.axml -->


<!-- 
頁面中使用 自定義組件 i1
1. 將 this.data.count 通過props傳遞給自定義組件
2. 自定義組件內部可以通過this.props獲取,并可以在其axml內部直接使用 count
-->
<i1 count="{{count}}">
    <!-- named slot 會渲染這行內容 -->
    <view slot="slot{{item}}" a:for="{{count}}">{{item}}</view> 


<!-- 
給named slot傳遞 渲染的內容,并使用其傳遞的參數(shù)
1. 這里會匹配自定義組件中的 <slot name="scope" value="{{o.value}}">
2. 使用其傳遞的參數(shù),即 c = {value: o.value}
-->
    <view slot="scope" slot-scope="c">{{c.value}}</view>


    count: {{count}} <!-- default slot 會渲染這行內容 -->
</i1>
<button onTap="plus">count+</button>
// /components/complex/i1.js
Component({
  data: {
    o: {
      value: "scope-value"
    }
  },
  onInit() { // 組件創(chuàng)建時觸發(fā)
    console.log("i1 onInit", this.props, this.data);
  },
  deriveDataFromProps(nextProps) { // 組件創(chuàng)建時觸發(fā)或更新時觸發(fā)
    console.log("i1 deriveDataFromProps", nextProps, this.props, this.data);
  },
  didMount() { // 組件創(chuàng)建完畢時觸發(fā)
    console.log("i1 didMount", this.props, this.data);
  },
  didUpdate(prevProps, prevData) { // 組件更新完畢時觸發(fā)
    console.log("i1 didUpdate", prevProps, prevData, this.props, this.data);
  },
  didUnmount() { // 組件刪除時觸發(fā)
    console.log("i1 didUnmount");
  },
  methods: {
    change() {
      this.setData({ 'o.value': "changed-scope-value" });
    }
  }
});
// /components/complex/f.sjs
export default function addOne(value) {
  return ++value;
}
<!-- /components/complex/i1.axml -->


<!-- 
sjs: safe/subset javascript
1. 可以在 axml 中運行的安全js腳本
2. 可使用其實現(xiàn)一些功能函數(shù)


詳見: /mini/framework/sjs
-->
<import-sjs name="addOne" from="./f.sjs"/> 


<!-- 
default slot: 默認插槽


會渲染使用者傳入的除 具名插槽(named slot) 以外的內容;
對于本示例: 就是頁面axml中的 count: {{count}}


詳見: /mini/framework/component-template#axml
-->
<slot/> 


<!-- 
使用 a:for 渲染列表
使用上面 import-sjs 中引入的 addOne 函數(shù)    
-->
<view a:for="{{addOne(count)}}">


<!-- 
named slot: 具名插槽
1. 通過 name 與使用者傳入內容的一一匹配
2. 如果匹配不到,會默認渲染 default


詳見: /mini/framework/component-template#axml
-->
    <slot name="slot{{item}}">default</slot> 
</view>


<view>
<!-- 
named slot: 具名插槽
1. 這里同樣是一個 具名插槽,同時會傳遞一些參數(shù)給使用者
2. 對于本示例,會傳遞 {value: o.value} 給使用者


詳見: /mini/framework/component-template#axml
-->
    <slot name="scope" value="{{o.value}}" /> 
</view>
<button onTap="change">change scope slot value</button>

本示例在 page 中 使用自定義組件 i1,并使用了小程序框架提供的如下關鍵技術:

  • 自定義組件體系 component2
  • axml支持靈活的使用 slot
  • axml中使用sjs

本示例初始渲染內容如下: 1559293964559-23393c80-e2f0-416a-9507-946212f83b9a.png

控制臺會依次打?。?/p>

i1 onInit
i1 deriveDataFromProps
i1 didMount

說明: 自定義組件創(chuàng)建階段依次觸發(fā): onInit、deriveDataFromProps、didMount 生命周期。

當我們點擊 count+ button的時候,頁面渲染如下:

2.png

控制臺依次打印:

i1 deriveDataFromProps
i1 didUpdate

說明:

  1. 自定義組件更新階段依次觸發(fā): deriveDataFromProps、didUpdate 生命周期。
  2. 外部 props 變化會觸發(fā) deriveDataFromProps。

點擊 change scope slot value button的時候,頁面渲染如下: 3.png

控制臺依次打?。?/p>

i1 deriveDataFromProps
i1 didUpdate

說明: 自定義組件 data 變化也會觸發(fā) deriveDataFromProps。

以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號