CML(Chameleon Markup Language)用于描述頁(yè)面的結(jié)構(gòu),我們知道 HTML 是有一套標(biāo)準(zhǔn)的語(yǔ)義化標(biāo)簽,例如 文本是 <span> 按鈕是 <button>。CML 同樣具有一套標(biāo)準(zhǔn)的標(biāo)簽,我們將標(biāo)簽定義為組件,CML 為用戶提供了一系列基礎(chǔ)組件。同時(shí) CML 中還支持模板語(yǔ)法,例如條件渲染、列表渲染,數(shù)據(jù)綁定等等。
框架為開發(fā)者提供了一系列基礎(chǔ)組件,開發(fā)者可以通過組合這些基礎(chǔ)組件進(jìn)行快速開發(fā)。詳細(xì)介紹請(qǐng)參考組件文檔。
什么是組件:
<tagname property="value">Content goes here ...</tagname>
注意:所有組件屬性都是小寫,以連字符-連接。
類型 | 描述 | 注解 |
---|---|---|
String | 字符串 | `"string"` |
Number | 數(shù)字 | `1, 1.5` |
Boolean | 布爾值 | `true,false` |
Array | 數(shù)組 | `[1, 'string']` |
Object | 對(duì)象 | `{key: value}` |
EventHandler | 事件處理函數(shù)名 | `handlerName`是組件中定義的事件處理函數(shù)名 |
所有組件都有以下屬性
屬性名 | 類型 | 描述 | 注解 |
---|---|---|---|
id | String | 組件唯一標(biāo)示 | 保證整個(gè)頁(yè)面唯一 |
class | String | 組件樣式類名 | 在cmss中定義的樣式類 |
style | String | 組件內(nèi)聯(lián)樣式 | 可動(dòng)態(tài)設(shè)置內(nèi)聯(lián)樣式 |
c-bind | EventHandler | 組件事件 |
CML 提供了內(nèi)置組件及擴(kuò)展組件,根據(jù)組件特殊性幾乎每個(gè)組件都有自己的特殊屬性,詳細(xì)屬性請(qǐng)查看組件文檔。
模板中綁定的數(shù)據(jù)來(lái)均來(lái)自于 data、computed 屬性。
數(shù)據(jù)綁定使用 Mustache 語(yǔ)法(雙大括號(hào)), {{}}之內(nèi)的可以是一些變量或者簡(jiǎn)單的表達(dá)式。
<view><text>{{ message }}</text></view>
<view id="item-{{id}}"> </view>
<view hidden="{{flag ? true : false}}"> <text>Hidden </text> </view>
<view><text>{{a + b}} + {{c}} + d </text></view>
<view c-if="{{length > 5}}"> </view>
class Index {
data = {
a: 1,
b: 2,
c: 3,
};
}
export default new Index();
view 中的內(nèi)容為 3 + 3 + d
<template>
<page title="chameleon">
<view><text>message:{{message}}</text></view>
<input c-model="{{message}}"></input>
</page>
</template>
<script>
class Comp {
data = {
message:'default-value'
}
watch = {
message(){
console.log('modelTest change');
}
}
}
export default new Comp();
</script>
<script cml-type="json">
{
"base": {}
}
</script>
c-model 元素上不支持再綁定 input 事件,如果對(duì)于輸入值變化之后想執(zhí)行一些操作,可以通過 watch 對(duì)應(yīng)的值來(lái)進(jìn)行;
父組件
<template>
<page title="chameleon">
<scroller height="{{-1}}">
<view><text>c-model的在組件上的使用</text></view>
<comp c-model="{{modelValueTest2}}"></comp>
<view
><text>組件使其改變{{ modelValueTest2 }}</text></view
>
</scroller>
</page>
</template>
<script>
class Index {
data = {
currentComp: 'comp1',
modelValueTest2: 'sss',
};
methods = {
handleClick() {
this.currentComp = this.currentComp === 'comp1' ? 'comp1' : 'comp2';
},
};
}
export default new Index();
</script>
<style>
.scroller-wrap {
display: flex;
flex-direction: column;
align-items: center;
}
</style>
<script cml-type="json">
{
"base": {
"usingComponents": {
"comp1":"/components/comp1",
"comp2":"/components/comp2"
}
},
"wx": {
"navigationBarTitleText": "index",
"backgroundTextStyle": "dark",
"backgroundColor": "#E2E2E2"
},
"alipay": {
"defaultTitle": "index",
"pullRefresh": false,
"allowsBounceVertical": "YES",
"titleBarColor": "#ffffff"
},
"baidu": {
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "white",
"navigationBarTitleText": "index",
"backgroundColor": "#ffffff",
"backgroundTextStyle": "dark",
"enablePullDownRefresh": false,
"onReachBottomDistance": 50
}
}
</script>
子組件
<template>
<view>
<input type="text" value="{{value}}" c-bind:input="handleInput" />
</view>
</template>
<script>
class Comp {
props = {
value: {
type: String,
default: 'default-value',
},
};
methods = {
handleInput(e) {
console.log('input', e);
this.$cmlEmit('input', {
value: e.detail.value,
});
},
};
}
export default new Comp();
</script>
<script cml-type="json">
{
"base": {}
}
</script>
注意 c-model 的值只能是 data 或者 computed 中的 key 值,不支持 modelValue.xxx 等需要二次計(jì)算的值;
在框架中,使用
c-if="{{ condition }}"
來(lái)判斷是否需要渲染該代碼塊:
<view c-if="{{condition}}">True</view>
也可以用 c-else-if 和 c-else 來(lái)添加一個(gè) else 塊:
<view c-if="{{length > 5}}"> <text>1 </text></view>
<view c-else-if="{{length > 2}}"> <text>2 </text></view>
<view c-else> <text>3 </text></view>
因?yàn)?c-if 是一個(gè)控制屬性,需要將它添加到一個(gè)標(biāo)簽上。如果要一次性判斷多個(gè)組件標(biāo)簽,可以使用一個(gè) \<block\> 標(biāo)簽將多個(gè)組件包裝起來(lái),并在上邊使用 c-if 控制屬性。
<block c-if="{{true}}">
<view> <text>view1 </text></view>
<view> <text>view2 </text></view>
</block>
注意: \<block\> 并不是一個(gè)組件,它僅僅是一個(gè)包裝元素,不會(huì)在頁(yè)面中做任何渲染,只接受控制屬性。
在組件上使用 c-for 控制屬性綁定一個(gè)數(shù)組,即可使用數(shù)組中各項(xiàng)的數(shù)據(jù)重復(fù)渲染該組件。 默認(rèn)數(shù)組的當(dāng)前項(xiàng)的下標(biāo)變量名默認(rèn)為 index,數(shù)組當(dāng)前項(xiàng)的變量名默認(rèn)為 item
<view c-for="{{array}}">
<text>{{index}}: {{item.message}}</text>
</view>
使用 c-for-item 可以指定數(shù)組當(dāng)前元素的變量名, 使用 c-for-index 可以指定數(shù)組當(dāng)前下標(biāo)的變量名:
<view c-for="{{array}}" c-for-index="idx" c-for-item="itemName">
<text> {{idx}}: {{itemName.message}}</text>
</view>
c-for 也可以嵌套,下邊是一個(gè)九九乘法表
<view c-for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" c-for-item="i">
<view c-for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" c-for-item="j">
<view v-if="{{i <= j}}">
<text> {{i}} * {{j}} = {{i * j}}</text>
</view>
</view>
</view>
類似 block c-if,也可以將 c-for 用在 \<block\> 標(biāo)簽上,以渲染一個(gè)包含多節(jié)點(diǎn)的結(jié)構(gòu)塊。例如:
<block c-for="{{[1, 2, 3]}}">
<view> <text>{{index}}: </text></view>
<view> <text>{{item}}</text> </view>
</block>
如果列表中項(xiàng)目的位置會(huì)動(dòng)態(tài)改變或者有新的項(xiàng)目添加到列表中,并且希望列表中的項(xiàng)目保持自己的特征和狀態(tài)(如 <input/> 中的輸入內(nèi)容,<switch/>的選中狀態(tài)),需要使用 c-key 來(lái)指定列表中項(xiàng)目的唯一的標(biāo)識(shí)符。~~~~
c-key 的值以兩種形式提供
1.字符串,代表在 for 循環(huán)的 array 中 item 的某個(gè) property,該 property 的值需要是列表中唯一的字符串或數(shù)字,且不能動(dòng)態(tài)改變。
2.保留關(guān)鍵字 *this 代表在 for 循環(huán)中的 item 本身,這種表示需要 item 本身是一個(gè)唯一的字符串或者數(shù)字,如: 當(dāng)數(shù)據(jù)改變觸發(fā)渲染層重新渲染的時(shí)候,會(huì)校正帶有 key 的組件,框架會(huì)確保他們被重新排序,而不是重新創(chuàng)建,以確保使組件保持自身的狀態(tài),并且提高列表渲染時(shí)的效率。
Chameleon 支持一些基礎(chǔ)的事件,保障各端效果一致運(yùn)行。如果你想要使用某個(gè)端特定的事件,請(qǐng)從業(yè)務(wù)出發(fā)使用多態(tài)組件或者多態(tài)接口差異化實(shí)現(xiàn)功能。
當(dāng)用戶點(diǎn)擊該組件的時(shí)候會(huì)在該組件邏輯對(duì)象的methods中尋找相應(yīng)的處理函數(shù)
<template>
<view id="tapTest" data-hi="WeChat" c-bind:tap="tapName">
<text>Click me!</text>
</view>
</template>
<script>
class Index {
methods = {
tapName(e) {
// 打印事件對(duì)象
console.log('事件對(duì)象:', e);
},
};
}
export default new Index();
</script>
chameleon 所有元素都支持基礎(chǔ)事件類型如下:
類型 | 觸發(fā)條件 |
---|---|
tap | 手指觸摸后馬上離開 |
touchstart | 手指觸摸動(dòng)作開始 |
touchmove | 手指觸摸后移動(dòng) |
touchend | 手指觸摸動(dòng)作結(jié)束 |
當(dāng)觸發(fā)事件時(shí),邏輯層綁定該事件的處理函數(shù)會(huì)收到一個(gè)事件對(duì)象。它有以下屬性:
名稱 | 類型 | 說(shuō)明 |
---|---|---|
type | String | 事件類型 |
timeStamp | Number | 頁(yè)面打開到觸發(fā)事件所經(jīng)過的毫秒數(shù) |
target | Object | 觸發(fā)事件的目標(biāo)元素 且 target = { id, dataset } |
currentTarget | Object | 綁定事件的目標(biāo)元素 且 currentTarget = { id, dataset } |
touches | Array | 觸摸事件中的屬性,當(dāng)前停留在屏幕中的觸摸點(diǎn)信息的數(shù)組 且 touches = [{ identifier, pageX, pageY, clientX, clientY }] |
changedTouches | Array | 觸摸事件中的屬性,當(dāng)前變化的觸摸點(diǎn)信息的數(shù)組 且 changedTouches = [{ identifier, pageX, pageY, clientX, clientY }] |
detail | Object | 自定義事件所攜帶的數(shù)據(jù)。 通過`$cmlEmit`方法觸發(fā)自定義事件,可以傳遞自定義數(shù)據(jù)即detail。具體下面`自定義事件`。 |
_originEvent | Object | CML 對(duì)各平臺(tái)的事件對(duì)象進(jìn)行統(tǒng)一,會(huì)把原始的事件對(duì)象放到_originEvent屬性中,當(dāng)需要特殊處理的可以進(jìn)行訪問。 |
屬性 | 類型 | 說(shuō)明 |
---|---|---|
id | String | 事件源組件的id |
dataset | Object | 事件源組件上由`data-`開頭的自定義屬性組成的集合 |
在組件中可以定義數(shù)據(jù),這些數(shù)據(jù)將會(huì)通過事件傳遞給 SERVICE。 書寫方式: 以 data-開頭,多個(gè)單詞由連字符-鏈接,不能有大寫(大寫會(huì)自動(dòng)轉(zhuǎn)成小寫)如 data-element-type,最終在 event.currentTarget.dataset 中會(huì)將連字符轉(zhuǎn)成駝峰 elementType。
示例:
<view data-alpha-beta="1" data-alphaBeta="2" c-bind:tap="bindViewTap"> DataSet Test </view>
<script>
class Index {
methods = {
bindViewTap: function(event) {
event.currentTarget.dataset.alphaBeta === 1; // - 會(huì)轉(zhuǎn)為駝峰寫法
event.currentTarget.dataset.alphabeta === 2; // 大寫會(huì)轉(zhuǎn)為小寫
},
};
}
export default new Index();
</script>
數(shù)組中的對(duì)象具有如下屬性:
屬性 | 類型 | 說(shuō)明 |
---|---|---|
identifier | Number | 觸摸點(diǎn)的標(biāo)識(shí)符 |
pageX, pageY | Number | 距離文檔左上角的距離,文檔的左上角為原點(diǎn) ,橫向?yàn)閄軸,縱向?yàn)閅軸 |
clientX, clientY | Number | 距離頁(yè)面可顯示區(qū)域(屏幕除去導(dǎo)航條)左上角距離,橫向?yàn)閄軸,縱向?yàn)閅軸 |
注意:返回值的單位為 px;可以通過chameleon-api中的 px2cpx進(jìn)行單位的轉(zhuǎn)化;
自定義事件用于父子組件之間的通信,父組件給子組件綁定自定義事件,子組件內(nèi)部觸發(fā)該事件。綁定事件的方法是以bind+事件名稱="事件處理函數(shù)的形式給組件添加屬性,規(guī)定事件名稱不能存在大寫字母觸發(fā)事件的方法是調(diào)用this.$cmlEmit(事件名稱,detail對(duì)象)。
注意:自定義事件名稱不支持click、scroll
例如: 子組件 child
<template>
<view c-bind:tap="triggerCustomEvent"><text>觸發(fā)自定義事件</text></view>
</template>
<script>
class Index {
data: {}
method: {
triggerCustomEvent(e) {
this.$cmlEmit('customevent', {
company: 'didi',
age: 18
})
}
}
}
export default new Index();
<script>
父組件
<template>
<child c-bind:customevent="customEventHandler">
</child>
</template>
<script>
class Index {
data = {}
method = {
customEventHandler(e) {
console.log(e)
}
}
}
export default new Index();
<script>
當(dāng)點(diǎn)擊child組件的按鈕時(shí),父組件中的 customEventHandler 方法中打印的 e 對(duì)象如下:
{
type: "customevent",
detail: {
company: "didi",
age: 18
}
}
事件綁定支持以下幾種形式(在內(nèi)聯(lián)語(yǔ)句中,$event代表事件對(duì)象)
<!-- 寫法(1) -->
<view c-bind:tap="handleElementTap"><text>觸發(fā)元素點(diǎn)擊事件</text></view>
<!-- 寫法(2) -->
<view
c-bind:tap="handleElementTap(1,2,3, 'message'+msg , $event)"><text>觸發(fā)元素點(diǎn)擊事件(1,2,3)</text></view>
<!-- 寫法(3) -->
<view c-bind:tap="handleElementTap()"><text>觸發(fā)元素點(diǎn)擊事件()</text></view>
**針對(duì)以上寫法返回的事件對(duì)象如下: **
寫法(1)調(diào)用事件函數(shù)輸出如下
'handleElementTap'[e];
寫法(2)調(diào)用事件函數(shù)輸出如下
'handleElementTap'[(1, 2, 3, 'messagetestEvent', e)];
寫法(3)調(diào)用事件函數(shù)輸出如下
'handleElementTap' []
chameleon-tool@0.2.0 + 的版本 支持了事件冒泡和阻止事件冒泡
注意:對(duì)于阻止事件冒泡,在內(nèi)聯(lián)事件傳參的情況下,需要傳遞 $event參數(shù);
<!-- 不會(huì)阻止冒泡 -->
<view c-catch:click="handleElementTap(1,2)"><text>觸發(fā)元素點(diǎn)擊事件</text></view>
<!-- 會(huì)阻止冒泡 -->
<view c-catch:click="handleElementTap(1,2,$event)"><text>觸發(fā)元素點(diǎn)擊事件</text></view>
<template>
<view class="root">
<view class="pad">
cml語(yǔ)法事件冒泡測(cè)試
</view>
<view c-bind:click="rootClick">
<text style="font-size: 40px;">{{ rootText }}</text>
<view class="outer" c-catch:click="parentClick">
<view>
<text style="font-size: 40px;">{{ parentText }}</text>
</view>
<text class="inner" c-bind:click="click">{{ innerText }}</text>
</view>
</view>
</view>
</template>
<script>
class Index {
methods = {
click: function(e) {
this.innerText = 'inner bubble';
console.log('this.innerText', this.innerText);
},
parentClick: function(e) {
this.parentText = 'parent bubble';
console.log('this.parentClick', this.parentClick);
},
rootClick: function(e) {
this.rootText = 'root bubble';
console.log('this.rootClick', this.rootClick);
},
};
}
export default new Index();
</script>
事件綁定的寫法同組件的屬性,以 key、value 的形式。 key 以 c-bind,然后跟上事件的類型,如 c-bind:tap、c-bind:touchstart。 value 是一個(gè)字符串,需要在對(duì)應(yīng)的邏輯對(duì)象中聲明的methods中聲明該方法。
不支持的語(yǔ)法 注意,事件綁定不支持直接傳入一個(gè)表達(dá)式,和綁定多個(gè)內(nèi)聯(lián)執(zhí)行函數(shù)比如
<div c-bind:tap="count++"></div>
<div c-bind:tap="handleTap1(); handleTap2()"></div>
component 接受兩個(gè)屬性
屬性名 | 說(shuō)明 |
---|---|
is | 接受一個(gè)計(jì)算屬性作為動(dòng)態(tài)渲染的標(biāo)簽名 |
shrinkcomponents | 接受 usingComponents 中的key值組成的字符串作為動(dòng)態(tài)組件選擇的范圍 |
注意,為了提高微信端的渲染效率,強(qiáng)烈建議加上 shrinkcomponents = "comp1,comp2,...",縮小動(dòng)態(tài)渲染的查找范圍,減少不必要的渲染開銷
<template>
<view class="page-container">
<view c-bind:tap="handleElementClick"><text>組件改變</text></view>
<component is="{{currentComp}}" shrinkcomponents="comp,comp1"></component>
</view>
</template>
<script>
class Index {
data = {
dataComp: 'comp',
};
computed = {
currentComp() {
return this.dataComp === 'comp' ? 'comp1' : 'comp';
},
};
methods = {
handleElementClick(a, b) {
console.log('handleElementClick', arguments, a, b);
this.dataComp = this.dataComp === 'comp' ? 'comp1' : 'comp';
},
};
}
export default new Index();
</script>
<script cml-type="json">
{
"base": {
"usingComponents": {
"comp":"./comp",
"comp1":"./comp1",
"comp2":"./comp2",
"comp3":"./comp3",
}
},
"wx": {
"navigationBarTitleText": "index",
"backgroundTextStyle": "dark",
"backgroundColor": "#E2E2E2"
},
"alipay": {
"defaultTitle": "index",
"pullRefresh": false,
"allowsBounceVertical": "YES",
"titleBarColor": "#ffffff"
},
"baidu": {
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "white",
"navigationBarTitleText": "index",
"backgroundColor": "#ffffff",
"backgroundTextStyle": "dark",
"enablePullDownRefresh": false,
"onReachBottomDistance": 50
}
}
</script>
component 動(dòng)態(tài)組件上同樣支持綁定事件,傳遞屬性;
比如
<component
is="{{currentComp}}"
type="upcaseEvent"
c-bind:upcaseEvent="handleUpcaseEvent"
id="{{id}}"
></component>
注意 : 小程序端是通過條件判斷來(lái)模擬 component is 的效果的,所以不要在 component 標(biāo)簽上在在寫 c-if c-else c-else-if 等條件判斷
根據(jù)表達(dá)式的真假值條件渲染元素
<div c-if="{{true}}">根據(jù)c-if的真假結(jié)果決定是否渲染</div>
用法
<div c-if="{{1 > 0.5}}">
Now you see me
</div>
<div c-else>
Now you don't
</div>
<div c-if="{{type === 'A'}}">
A
</div>
<div c-else-if="{{type === 'B'}}">
B
</div>
<div c-else-if="{{type === 'C'}}">
C
</div>
<div c-else>
Not A/B/C
</div>
<view c-for="{{array}}" c-for-index="idx" c-for-item="itemName">
<text> {{idx}}: {{itemName.message}}</text>
</view>
父組件
<view><text>c-model的使用</text></view>
<input type="text" c-model="{{modelValueTest}}" />
<text>{{modelValueTest}}</text>
<comp c-model="{{modelValueTest2}}"></comp>
<view><text>組件使其改變{{modelValueTest2}}</text></view>
子組件
<template>
<view>
<input type="text" :value="value" c-bind:input="handleInput" />
</view>
</template>
<script>
methods = {
handleInput(e){
console.log('input',e);
this.$cmlEmit('input', {
value: Date.now()
})
}
}
}
</script>
** $cmlEmit 的事件名必須是 'input', 傳入的參數(shù)需要有一個(gè)更新的 value 作為 key, 其屬性值作為新值進(jìn)行更新;**
<view c-text="{{message}}"></view>
不支持組件的 c-text
<view c-show="{{elementShow}}">
<text>測(cè)試元素c-show</text>
</view>
<view><text>組件v-show</text></view>
<comp c-show="{{elementShow}}"></comp>
傳入的值必須由createAnimation返回
<template>
<text c-animation="{{animationData}}" c-bind:click="click">hello world</text>
</template>
<script>
import cml from 'cml目錄';
const animation = cml.createAnimation();
class Index {
data = {
animationData: {},
};
methods = {
click: function() {
this.animationData = animation
.opacity(0.1)
.step({})
.export();
},
};
}
export default new Index();
</script>
更多建議: