CML(Chameleon Markup Language)用于描述頁面的結(jié)構(gòu),我們知道 HTML 是有一套標(biāo)準(zhǔn)的語義化標(biāo)簽,例如 文本是 <span> 按鈕是 <button>。CML 同樣具有一套標(biāo)準(zhǔn)的標(biāo)簽,我們將標(biāo)簽定義為組件,CML 為用戶提供了一系列基礎(chǔ)組件。同時 CML 中還支持模板語法,例如條件渲染、列表渲染,數(shù)據(jù)綁定等等。
框架為開發(fā)者提供了一系列基礎(chǔ)組件,開發(fā)者可以通過組合這些基礎(chǔ)組件進行快速開發(fā)。詳細介紹請參考組件文檔。
什么是組件:
<tagname property="value">Content goes here ...</tagname>
注意:所有組件屬性都是小寫,以連字符-連接。
類型 | 描述 | 注解 |
---|---|---|
String | 字符串 | `"string"` |
Number | 數(shù)字 | `1, 1.5` |
Boolean | 布爾值 | `true,false` |
Array | 數(shù)組 | `[1, 'string']` |
Object | 對象 | `{key: value}` |
EventHandler | 事件處理函數(shù)名 | `handlerName`是組件中定義的事件處理函數(shù)名 |
所有組件都有以下屬性
屬性名 | 類型 | 描述 | 注解 |
---|---|---|---|
id | String | 組件唯一標(biāo)示 | 保證整個頁面唯一 |
class | String | 組件樣式類名 | 在cmss中定義的樣式類 |
style | String | 組件內(nèi)聯(lián)樣式 | 可動態(tài)設(shè)置內(nèi)聯(lián)樣式 |
c-bind | EventHandler | 組件事件 |
CML 提供了內(nèi)置組件及擴展組件,根據(jù)組件特殊性幾乎每個組件都有自己的特殊屬性,詳細屬性請查看組件文檔。
模板中綁定的數(shù)據(jù)來均來自于 data、computed 屬性。
數(shù)據(jù)綁定使用 Mustache 語法(雙大括號), {{}}之內(nèi)的可以是一些變量或者簡單的表達式。
<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 事件,如果對于輸入值變化之后想執(zhí)行一些操作,可以通過 watch 對應(yīng)的值來進行;
父組件
<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 等需要二次計算的值;
在框架中,使用
c-if="{{ condition }}"
來判斷是否需要渲染該代碼塊:
<view c-if="{{condition}}">True</view>
也可以用 c-else-if 和 c-else 來添加一個 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>
因為 c-if 是一個控制屬性,需要將它添加到一個標(biāo)簽上。如果要一次性判斷多個組件標(biāo)簽,可以使用一個 \<block\> 標(biāo)簽將多個組件包裝起來,并在上邊使用 c-if 控制屬性。
<block c-if="{{true}}">
<view> <text>view1 </text></view>
<view> <text>view2 </text></view>
</block>
注意: \<block\> 并不是一個組件,它僅僅是一個包裝元素,不會在頁面中做任何渲染,只接受控制屬性。
在組件上使用 c-for 控制屬性綁定一個數(shù)組,即可使用數(shù)組中各項的數(shù)據(jù)重復(fù)渲染該組件。 默認(rèn)數(shù)組的當(dāng)前項的下標(biāo)變量名默認(rèn)為 index,數(shù)組當(dā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 也可以嵌套,下邊是一個九九乘法表
<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)簽上,以渲染一個包含多節(jié)點的結(jié)構(gòu)塊。例如:
<block c-for="{{[1, 2, 3]}}">
<view> <text>{{index}}: </text></view>
<view> <text>{{item}}</text> </view>
</block>
如果列表中項目的位置會動態(tài)改變或者有新的項目添加到列表中,并且希望列表中的項目保持自己的特征和狀態(tài)(如 <input/> 中的輸入內(nèi)容,<switch/>的選中狀態(tài)),需要使用 c-key 來指定列表中項目的唯一的標(biāo)識符。~~~~
c-key 的值以兩種形式提供
1.字符串,代表在 for 循環(huán)的 array 中 item 的某個 property,該 property 的值需要是列表中唯一的字符串或數(shù)字,且不能動態(tài)改變。
2.保留關(guān)鍵字 *this 代表在 for 循環(huán)中的 item 本身,這種表示需要 item 本身是一個唯一的字符串或者數(shù)字,如: 當(dāng)數(shù)據(jù)改變觸發(fā)渲染層重新渲染的時候,會校正帶有 key 的組件,框架會確保他們被重新排序,而不是重新創(chuàng)建,以確保使組件保持自身的狀態(tài),并且提高列表渲染時的效率。
Chameleon 支持一些基礎(chǔ)的事件,保障各端效果一致運行。如果你想要使用某個端特定的事件,請從業(yè)務(wù)出發(fā)使用多態(tài)組件或者多態(tài)接口差異化實現(xiàn)功能。
當(dāng)用戶點擊該組件的時候會在該組件邏輯對象的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) {
// 打印事件對象
console.log('事件對象:', e);
},
};
}
export default new Index();
</script>
chameleon 所有元素都支持基礎(chǔ)事件類型如下:
類型 | 觸發(fā)條件 |
---|---|
tap | 手指觸摸后馬上離開 |
touchstart | 手指觸摸動作開始 |
touchmove | 手指觸摸后移動 |
touchend | 手指觸摸動作結(jié)束 |
當(dāng)觸發(fā)事件時,邏輯層綁定該事件的處理函數(shù)會收到一個事件對象。它有以下屬性:
名稱 | 類型 | 說明 |
---|---|---|
type | String | 事件類型 |
timeStamp | Number | 頁面打開到觸發(fā)事件所經(jīng)過的毫秒數(shù) |
target | Object | 觸發(fā)事件的目標(biāo)元素 且 target = { id, dataset } |
currentTarget | Object | 綁定事件的目標(biāo)元素 且 currentTarget = { id, dataset } |
touches | Array | 觸摸事件中的屬性,當(dāng)前停留在屏幕中的觸摸點信息的數(shù)組 且 touches = [{ identifier, pageX, pageY, clientX, clientY }] |
changedTouches | Array | 觸摸事件中的屬性,當(dāng)前變化的觸摸點信息的數(shù)組 且 changedTouches = [{ identifier, pageX, pageY, clientX, clientY }] |
detail | Object | 自定義事件所攜帶的數(shù)據(jù)。 通過`$cmlEmit`方法觸發(fā)自定義事件,可以傳遞自定義數(shù)據(jù)即detail。具體下面`自定義事件`。 |
_originEvent | Object | CML 對各平臺的事件對象進行統(tǒng)一,會把原始的事件對象放到_originEvent屬性中,當(dāng)需要特殊處理的可以進行訪問。 |
屬性 | 類型 | 說明 |
---|---|---|
id | String | 事件源組件的id |
dataset | Object | 事件源組件上由`data-`開頭的自定義屬性組成的集合 |
在組件中可以定義數(shù)據(jù),這些數(shù)據(jù)將會通過事件傳遞給 SERVICE。 書寫方式: 以 data-開頭,多個單詞由連字符-鏈接,不能有大寫(大寫會自動轉(zhuǎn)成小寫)如 data-element-type,最終在 event.currentTarget.dataset 中會將連字符轉(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; // - 會轉(zhuǎn)為駝峰寫法
event.currentTarget.dataset.alphabeta === 2; // 大寫會轉(zhuǎn)為小寫
},
};
}
export default new Index();
</script>
數(shù)組中的對象具有如下屬性:
屬性 | 類型 | 說明 |
---|---|---|
identifier | Number | 觸摸點的標(biāo)識符 |
pageX, pageY | Number | 距離文檔左上角的距離,文檔的左上角為原點 ,橫向為X軸,縱向為Y軸 |
clientX, clientY | Number | 距離頁面可顯示區(qū)域(屏幕除去導(dǎo)航條)左上角距離,橫向為X軸,縱向為Y軸 |
注意:返回值的單位為 px;可以通過chameleon-api中的 px2cpx進行單位的轉(zhuǎn)化;
自定義事件用于父子組件之間的通信,父組件給子組件綁定自定義事件,子組件內(nèi)部觸發(fā)該事件。綁定事件的方法是以bind+事件名稱="事件處理函數(shù)的形式給組件添加屬性,規(guī)定事件名稱不能存在大寫字母觸發(fā)事件的方法是調(diào)用this.$cmlEmit(事件名稱,detail對象)。
注意:自定義事件名稱不支持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)點擊child組件的按鈕時,父組件中的 customEventHandler 方法中打印的 e 對象如下:
{
type: "customevent",
detail: {
company: "didi",
age: 18
}
}
事件綁定支持以下幾種形式(在內(nèi)聯(lián)語句中,$event代表事件對象)
<!-- 寫法(1) -->
<view c-bind:tap="handleElementTap"><text>觸發(fā)元素點擊事件</text></view>
<!-- 寫法(2) -->
<view
c-bind:tap="handleElementTap(1,2,3, 'message'+msg , $event)"><text>觸發(fā)元素點擊事件(1,2,3)</text></view>
<!-- 寫法(3) -->
<view c-bind:tap="handleElementTap()"><text>觸發(fā)元素點擊事件()</text></view>
**針對以上寫法返回的事件對象如下: **
寫法(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 + 的版本 支持了事件冒泡和阻止事件冒泡
注意:對于阻止事件冒泡,在內(nèi)聯(lián)事件傳參的情況下,需要傳遞 $event參數(shù);
<!-- 不會阻止冒泡 -->
<view c-catch:click="handleElementTap(1,2)"><text>觸發(fā)元素點擊事件</text></view>
<!-- 會阻止冒泡 -->
<view c-catch:click="handleElementTap(1,2,$event)"><text>觸發(fā)元素點擊事件</text></view>
<template>
<view class="root">
<view class="pad">
cml語法事件冒泡測試
</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 是一個字符串,需要在對應(yīng)的邏輯對象中聲明的methods中聲明該方法。
不支持的語法 注意,事件綁定不支持直接傳入一個表達式,和綁定多個內(nèi)聯(lián)執(zhí)行函數(shù)比如
<div c-bind:tap="count++"></div>
<div c-bind:tap="handleTap1(); handleTap2()"></div>
component 接受兩個屬性
屬性名 | 說明 |
---|---|
is | 接受一個計算屬性作為動態(tài)渲染的標(biāo)簽名 |
shrinkcomponents | 接受 usingComponents 中的key值組成的字符串作為動態(tài)組件選擇的范圍 |
注意,為了提高微信端的渲染效率,強烈建議加上 shrinkcomponents = "comp1,comp2,...",縮小動態(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 動態(tài)組件上同樣支持綁定事件,傳遞屬性;
比如
<component
is="{{currentComp}}"
type="upcaseEvent"
c-bind:upcaseEvent="handleUpcaseEvent"
id="{{id}}"
></component>
注意 : 小程序端是通過條件判斷來模擬 component is 的效果的,所以不要在 component 標(biāo)簽上在在寫 c-if c-else c-else-if 等條件判斷
根據(jù)表達式的真假值條件渲染元素
<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ù)需要有一個更新的 value 作為 key, 其屬性值作為新值進行更新;**
<view c-text="{{message}}"></view>
不支持組件的 c-text
<view c-show="{{elementShow}}">
<text>測試元素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>
更多建議: