CML 支持簡潔的組件化編程。
開發(fā)者可以將頁面內(nèi)的功能模塊抽象成自定義組件,以便在不同的頁面中重復(fù)使用;也可以將復(fù)雜的頁面拆分成多個低耦合的模塊,有助于代碼維護(hù)。
類似頁面,自定義組件由 <template> <script> <style> <script cml-type="json"> 4 部分組成。
要編寫一個自定義組件,可以在 json 中進(jìn)行自定義組件聲明(將 component 字段設(shè)為 true,這是可選操作,因?yàn)?CML 會在引用這個文件時自動識別自定義組件):
{
"component": true
}
接下來,在 <template> 中編寫組件模板,在 <style> 中加入組件樣式,它們的寫法與頁面的寫法類似。具體細(xì)節(jié)和注意事項(xiàng)參見組件模板和樣式。
代碼示例:
<!-- 這是自定義組件的內(nèi)部CML結(jié)構(gòu) -->
<view class="inner">
{{innerText}}
</view>
<slot></slot>
/* 這里的樣式只應(yīng)用于這個自定義組件 */
.inner {
color: red;
}
注意:在組件 CMSS 中不應(yīng)使用 ID 選擇器、屬性選擇器和標(biāo)簽名選擇器。
組件的屬性值和內(nèi)部數(shù)據(jù)將被用于組件 CML 的渲染,其中,屬性值是可由組件外部傳入的。
代碼示例:
<script>
class CustomCom {
props = {
title: String,
innerText: {
type: String,
},
content: {
type: Object,
default: {},
},
list: {
type: Array,
default: [],
},
};
data = {};
computed = {};
watch = {};
methods = {};
beforeCreate() {}
created() {}
beforeMount() {}
mounted() {}
beforeDestroy() {}
destroyed() {}
}
export default new CustomCom();
</script>
使用已注冊的自定義組件前,首先要在頁面的 <script cml-type="json"> 中進(jìn)行引用聲明。
此時需要提供每個自定義組件的標(biāo)簽名和對應(yīng)的自定義組件文件路徑(相對路徑或者絕對路徑):
{
"usingComponents": {
"component-tag-name": "path/to/the/custom/component"
}
}
這樣,在頁面的 CML 中就可以像使用基礎(chǔ)組件一樣使用自定義組件。節(jié)點(diǎn)名即自定義組件的標(biāo)簽名,節(jié)點(diǎn)屬性即傳遞給組件的屬性值。
代碼示例:
<view>
<!-- 以下是對一個自定義組件的引用 -->
<component-tag-name title="xxx" inner-text="Some text"></component-tag-name>
</view>
自定義組件的 CML 節(jié)點(diǎn)結(jié)構(gòu)在與數(shù)據(jù)結(jié)合之后,將被插入到引用位置內(nèi)。
一些需要注意的細(xì)節(jié):
**注意,**是否在頁面文件中使用 usingComponents 會使得頁面的 this 對象的原型稍有差異,包括:
類似于頁面,自定義組件擁有自己的 <template> 模板和 <style> 樣式。
首先我們通過 cml init project 生成一個 CML 項(xiàng)目,然后按照以下操作指引,看下如何使用 CML 的組件
cml init component
選擇普通組件
輸入 component-tag-namecomponent-tag-name
在 src/pages/index/index.cml中引入這個組件
"usingComponents": {
"component-tag-name":"/components/component-tag-name/component-tag-name"
}
組件模板的寫法與頁面模板相同。組件模板與組件數(shù)據(jù)結(jié)合后生成的節(jié)點(diǎn)樹,將被插入到組件的引用位置上。
在組件模板中可以提供一個 <slot> 節(jié)點(diǎn),用于承載組件引用時提供的子節(jié)點(diǎn)。
代碼示例:
<!-- component-tag-name.cml -->
<!-- 組件模板 -->
<view class="wrapper">
<view>這里是組件的內(nèi)部節(jié)點(diǎn)</view>
<slot></slot>
</view>
<!-- index.cml -->
<!-- 引用組件的頁面模板 -->
<view>
<component-tag-name>
<!-- 這部分內(nèi)容將被放置在組件 <slot> 的位置上 -->
<view>這里是插入到組件slot中的內(nèi)容</view>
</component-tag-name>
</view>
可以使用數(shù)據(jù)綁定,這樣就可以向子組件的屬性傳遞動態(tài)數(shù)據(jù)。
代碼示例:
<!-- 引用組件的頁面模板 -->
<view>
<component-tag-name prop-a="{{dataFieldA}}" prop-b="{{dataFieldB}}">
<!-- 這部分內(nèi)容將被放置在組件 <slot> 的位置上 -->
<view>這里是插入到組件slot中的內(nèi)容</view>
</component-tag-name>
</view>
在以上例子中,組件的屬性 propA 和 propB 將收到頁面?zhèn)鬟f的數(shù)據(jù)。頁面可以通過 this.dataFieldA、this.dataFieldB 來改變綁定的數(shù)據(jù)字段。
注意:這樣的數(shù)據(jù)綁定只能傳遞 JSON 兼容數(shù)據(jù)。
在組件的 <template> 中可以包含 slot 節(jié)點(diǎn),用于承載組件使用者提供的 CML 結(jié)構(gòu)。
支持通過具名插槽的方式在模板中使用多個 slot
<!-- component-tag-name.cml -->
<template>
<view>
<view>組件模板的slot</view>
<slot name="before"></slot>
<slot></slot>
<slot name="after"></slot>
</view>
</template>
然后在父頁面 src/pages/index/index.cml中
<template>
<component-tag-name>
<view>this is from index</view>
<view slot="before">this is before from index</view>
<view slot="after">this is after from index</view>
<view>this is from index aaaa</view>
</component-tag-name>
</template>
組件對應(yīng) style 標(biāo)簽內(nèi)的樣式,只對當(dāng)前節(jié)點(diǎn)生效。編寫組件樣式時,需要注意以下幾點(diǎn):
#a {
} /* 在組件中不能使用 */
[a] {
} /* 在組件中不能使用 */
button {
} /* 在組件中不能使用 */
.a > .b {
} /* 除非 .a 是 view 組件節(jié)點(diǎn),否則不一定會生效 */
view {
} /* 不支持元素選擇器 */
CML 擴(kuò)展了多態(tài)樣式,用于針對對于不同端有不同的樣式需求的情況參考
在 .cml 文件 <script> 代碼塊 export default 的對象實(shí)例,可用于定義組件,指定組件的屬性、數(shù)據(jù)、方法等。
cml init component
選擇普通組件
輸入 component-tag-name
定義如下:
字段名 | 類型 | 說明 |
---|---|---|
props | Object | 聲明當(dāng)前組件可接收數(shù)據(jù)屬性 props = { type, default } type 為數(shù)據(jù)類型,default 為數(shù)據(jù)默認(rèn)值 |
data | Object | CML 模板可直接使用的響應(yīng)數(shù)據(jù),是連接視圖層的樞紐 |
methods | Object | 處理業(yè)務(wù)邏輯與交互邏輯的方法 |
watch | Object | 偵聽屬性,監(jiān)聽數(shù)據(jù)的變化,觸發(fā)相應(yīng)操作 |
computed | Object | CML 模板可直接使用的計算屬性數(shù)據(jù),也是連接視圖層的樞紐 |
beforeCreate | Function | 例初始化之后,數(shù)據(jù)和方法掛在到實(shí)例之前 一個頁面只會返回一次 |
created | Function | 數(shù)據(jù)及方法掛載完成 |
beforeMount | Function | 開始掛載已經(jīng)編譯完成的 cml 到對應(yīng)的節(jié)點(diǎn)時 |
mounted | Function | cml 模板編譯完成,且渲染到 dom 中完成 |
beforeDestroy | Function | 實(shí)例銷毀之前 |
destroyed | Function | 實(shí)例銷毀后 |
組件間的通信方式有以下幾種:
代碼示例
<!-- index.cml -->
<template>
<view>
<component-tag-name parent-prop="{{parent}}"> </component-tag-name>
</view>
</template>
<script>
class Index {
data = {
parent: { msg: 'this is parent message' },
};
}
export default new Index();
</script>
<!-- component-tag-name.cml -->
<template>
<view>
<view>{{ parentProp.msg }}</view>
</view>
</template>
<script>
class ComponentTagName {
props = {
parentProp: {
type: Object,
default: {},
},
};
}
export default new ComponentTagName();
</script>
代碼示例
<!-- index.cml -->
<template>
<view>
<component-tag-name c-bind:parentevent="handleParentEvent"> </component-tag-name>
</view>
</template>
<script>
class Index {
methods = {
handleParentEvent(...args) {
console.log(...args);
},
};
}
export default new Index();
</script>
<!-- component-tag-name.cml -->
<template>
<view>
<view c-bind:tap="handleClick"></view>
</view>
</template>
<script>
class ComponentTagName {
methods = {
handleClick() {
this.$cmlEmit('parentevent', {
value: 'this is from child',
});
},
};
}
export default new ComponentTagName();
</script>
更多建議: