CML - 類 Vue 語法

2020-05-14 14:19 更新

為了降低學(xué)習(xí)成本,獨(dú)立支持了 vue 的指令子集,你可以在模板添加一個(gè) lang 屬性 <template lang="vue"> 即可使用。 注意必須在組件根元素上 template 上加 lang='vue'

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

模板中綁定的數(shù)據(jù)來均來自于 data、computed 屬性。

模板語法

數(shù)據(jù)綁定使用 Mustache 語法(雙大括號)將變量包起來,可以作用于:

內(nèi)容

<view><text>{{ message }}</text></view>

組件屬性

<view :id="dynamicId"> </view> 或者 v-bind view v-bind:id="dynamicId"

v-model

應(yīng)用于表單元素

<template lang='vue'>
  <page title="chameleon">
       <view><text>message:{{message}}</text></view>
       <input v-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>

v-model 元素上不支持再綁定 input 事件,如果對于輸入值變化之后想執(zhí)行一些操作,可以通過 watch 對應(yīng)的值來進(jìn)行;

應(yīng)用于父子組件之間

父組件

<template lang="vue">
  <page title="chameleon">
    <view><text>c-model的在組件上的使用</text></view>
    <comp v-model="modelValueTest2" ></comp>
    <view><text>組件使其改變{{modelValueTest2}}</text></view>
  </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"
    }
  }
}
</script>

子組件

<template lang="vue">
  <view>
    <input type="text" :value="value" v-on:input="handleInput"/>
  </view>    
</template>

<script>
class Comp {
  props = {
    value: {
      type: String,
      default: 'default-value',
    },
  };
  methods = {
    handleInput(e) {
      console.log('input', e);
      debugger;
      this.$cmlEmit('input', {
        value: e.detail.value,
      });
    },
  };
}
export default new Comp();
</script>
<script cml-type="json">
{
  "base": {}
}
</script>

Javascript 表達(dá)式

在模板內(nèi)容中

{
  {
    number + 1;
  }
}

{
  {
    ok ? 'YES' : 'NO';
  }
}

{
  {
    message
      .split('')
      .reverse()
      .join('');
  }
}

算數(shù)運(yùn)算

<view><text>{{a + b}} + {{c}} + d</text></view>
class Index {
  data = {
    a: 1,
    b: 2,
    c: 3,
  };
}
export default new Index();

view 中的內(nèi)容為 3 + 3 + d。

字符串運(yùn)算

<view><text>{{"hello" + name}}</text></view>

特別注意:模板中的字符串都要使用雙引號,不能使用單引號。

數(shù)據(jù)路徑運(yùn)算

<view><text>{{object.key}}: {{array[0]}}</text></view>
class Index {
  data = {
    object: {
      key: 'Hello ',
    },
    array: ['MINA'],
  };
}
export default new Index();

Bug & Tips

  • 使用 component 語法的時(shí)候,為了提高微信端的渲染效率,建議加上 shrinkComponents = "comp1,comp2,...",縮小動(dòng)態(tài)渲染的查找范圍,減少不必要的渲染開銷;
  • 注意 v-model 的值只能是 data 或者 computed 中的 key 值,不支持 modelValue.xxx 等需要二次計(jì)算的值;

條件渲染

v-if

在框架中,使用

v-if="condition"

來判斷是否需要渲染該代碼塊:

<view v-if="condition">True</view>

也可以用 v-else-if 和 v-else 來添加一個(gè) else 塊:

<view v-if="length > 5"><text>1</text></view>
<view v-else-if="length > 2"><text>2</text></view>
<view v-else><text>3</text></view>

block v-if

因?yàn)?v-if 是一個(gè)控制屬性,需要將它添加到一個(gè)標(biāo)簽上。如果要一次性判斷多個(gè)組件標(biāo)簽,可以使用一個(gè) \<block\> 標(biāo)簽將多個(gè)組件包裝起來,并在上邊使用 v-if 控制屬性。

<block v-if="true">
  <view><text>view1</text></view>
  <view><text>view2</text></view>
</block>

注意:: \<block\> 并不是一個(gè)組件,它僅僅是一個(gè)包裝元素,不會(huì)在頁面中做任何渲染,只接受控制屬性。

Bug & Tips

  • 不要與 c-if c-else-if c-else 混用

列表渲染

v-for

在組件上使用 v-for 控制屬性綁定一個(gè)數(shù)組,即可使用數(shù)組中各項(xiàng)的數(shù)據(jù)重復(fù)渲染該組件。

<view v-for="(item, index) in array">
  <text>{{index}}: {{item.message}}</text>
</view>
<view v-for="(item, index) in array" :key="index">
  <text> {{index}}: {{item.message}}</text>
</view>
<view v-for="(item, index) in array" :key="item.id">
  <text> {{index}}: {{item.message}}</text>
</view>

block v-for

類似 block v-if,也可以將 v-for 用在 \<block\> 標(biāo)簽上,以渲染一個(gè)包含多節(jié)點(diǎn)的結(jié)構(gòu)塊。例如:

<block v-for="(item, index) in [1, 2, 3]">
  <view> <text>{{index}}: </text></view>
  <view> <text>{{item}}</text> </view>
</block>

:key

1.如果 :key="item.id",那么就是 vue 中正常的語法。

2.如果 :key="item",那么在微信端會(huì)被渲染成 wx:key="*this"; 保留關(guān)鍵字 *this 代表在 for 循環(huán)中的 item 本身,這種表示需要 item 本身是一個(gè)唯一的字符串或者數(shù)字,如: 當(dāng)數(shù)據(jù)改變觸發(fā)渲染層重新渲染的時(shí)候,會(huì)校正帶有 key 的組件,框架會(huì)確保他們被重新排序,而不是重新創(chuàng)建,以確保使組件保持自身的狀態(tài),并且提高列表渲染時(shí)的效率。

Bug & Tips

  • 不要與 c-for c-for-index c-for-item c-key 這些語法混用
  • vue 的 v-for 相關(guān)語法都可以使用,但是需要注意一點(diǎn)就是只支持?jǐn)?shù)組形式的被遍歷值

事件

Chameleon 支持一些基礎(chǔ)的事件,保障各端效果一致運(yùn)行。如果你想要使用某個(gè)端特定的事件,請從業(yè)務(wù)出發(fā)使用多態(tài)組件或者多態(tài)接口差異化實(shí)現(xiàn)功能。

主要擴(kuò)展了事件的綁定:加強(qiáng)了符合 vue 語法的事件綁定;

事件綁定

主要增強(qiáng)了可以通過 v-on @這種形式去綁定事件;

<view v-on:click="handleClick" @tap="handleTap"></view>
<template lang="vue">
<view id="tapTest"  @tap="tapName" v-on:click="handleClick"> <text>Click me!</text> </view>
</template>
<script>
class Index {
  data = {};
  methods = {
    tapName() {
      console.log(e);
    },
  };
}
export default new Index();
</script>

事件類型

事件類型列表:

類型觸發(fā)條件
touchstart手指觸摸動(dòng)作開始
touchmove手指觸摸后移動(dòng)
touchend手指觸摸動(dòng)作結(jié)束
tap手指觸摸后馬上離開

### 事件對象 當(dāng)組件觸發(fā)事件時(shí),邏輯層綁定該事件的處理函數(shù)會(huì)收到一個(gè)事件對象。chameleon將事件綁定做了一層代理,將各平臺(tái)的事件對象做統(tǒng)一,統(tǒng)一后的事件對象有如下屬性:

名稱類型說明
typeString事件類型
timeStampNumber頁面打開到觸發(fā)事件所經(jīng)過的毫秒數(shù)
targetObject觸發(fā)事件的目標(biāo)元素 且 target = {id,dateset}
currentTargetObject綁定事件的目標(biāo)元素 且 currentTarget = {id,dataset}
changedTouchesArray觸摸事件中的屬性,當(dāng)前變化的觸摸點(diǎn)信息的數(shù)組 且 changedTouches = [{ identifier, pageX, pageY, clientX, clientY }]
detailObject自定義事件所攜帶的數(shù)據(jù)。 通過$cmlEmit方法觸發(fā)自定義事件,可以傳遞自定義數(shù)據(jù)即 detail。具體下面自定義事件
_originEventObjectCML 對各平臺(tái)的事件對象進(jìn)行統(tǒng)一,會(huì)把原始的事件對象放到_originEvent 屬性中,當(dāng)需要特殊處理的可以進(jìn)行訪問。

target && currentTarget

屬性類型說明
idString事件源組件的 id
datasetObject事件源組件上由data-開頭的自定義屬性的集合

dataset

在組件中可以定義數(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>

changedTouches 事件屬性

數(shù)組中的對象有如下屬性:

屬性類型說明
identifierNumber觸摸點(diǎn)的標(biāo)識符
pageX
pageY
Number距離文檔左上角的距離,文檔的左上角為原點(diǎn),橫向?yàn)?X 軸,縱向?yàn)?Y 軸
clientX
clientY
Number距離頁面可顯示區(qū)域(屏幕除去導(dǎo)航條)左上角距離,橫向?yàn)?X 軸,縱向?yàn)?Y 軸

注意:返回值的單位為 px;可以通過chameleon-api中的 px2cpx進(jìn)行單位的轉(zhuǎn)化;

自定義事件

自定義事件用于父子組件之間的通信,父組件給子組件綁定自定義事件,子組件內(nèi)部觸發(fā)該事件。規(guī)定事件名稱不能存在大寫字母觸發(fā)事件的方法是調(diào)用this.$cmlEmit(事件名稱,detail對象)。

注意:自定義事件名稱不支持click、scroll

例如: 子組件 yyl-com

<template>
 <view @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>
  <yyl-com c-bind:customevent="customEventHandler">
  </yyl-com>
</template>
<script>
class Index {
  data = {}
  method = {
    customEventHandler(e) {
      console.log(e)
    }
  }
}
export default new Index();
<script>

當(dāng)點(diǎn)擊yyl-com組件的按鈕時(shí),父組件中的 customEventHandler 方法中打印的 e 對象如下:

{
  type: "customevent",
  detail: {
    company: "didi",
    age: 18
  }
}

支持的語法

事件綁定支持以下幾種形式(在內(nèi)聯(lián)語句中,$event代表事件對象)

<!-- 寫法(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>

**針對以上寫法返回的事件對象如下: **

寫法(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 + 的版本 支持了事件冒泡和阻止事件冒泡

vue語法下僅僅擴(kuò)展了 .stop;

注意:對于阻止事件冒泡,在內(nèi)聯(lián)事件傳參的情況下,需要傳遞 $event參數(shù);

<!-- 不會(huì)阻止冒泡 -->
<view v-on:click.stop="handleElementTap(1, 2)"><text>觸發(fā)元素點(diǎn)擊事件</text></view>
<!-- 會(huì)阻止冒泡 -->
<view v-on:click.stop="handleElementTap(1, 2, $event)"><text>觸發(fā)元素點(diǎn)擊事件</text></view>
<template lang="vue">
  <view class="root">   
    <view class="pad">
      vue語法事件冒泡測試
    </view>
    <view @click="rootClick">
      <text style="font-size: 40px;">{{rootText}}</text>
      <view class="outer" @click="parentClick">
        <view>
          <text style="font-size: 40px;">{{parentText}}</text>
        </view>
        <text class="inner" @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>

Bug & Tips

不支持的語法

注意,事件綁定不支持直接傳入一個(gè)表達(dá)式,和綁定多個(gè)內(nèi)聯(lián)執(zhí)行函數(shù)比如

<div c-bind:tap="count++"></div>
<div c-bind:tap="handleTap1(); handleTap2()"></div>

指令

v-if

根據(jù)表達(dá)式的真假值條件渲染元素

<div v-if="true">根據(jù)v-if的真假結(jié)果決定是否渲染</div>

v-else

  • 不需要表達(dá)式
  • 限制:前一個(gè)兄弟元素必須有 v-if 或者 v-else-if

用法

<div v-if="1 > 0.5">
  Now you see me
</div>
<div v-else>
  Now you don't
</div>

v-else-if

  • 限制:前一個(gè)兄弟元素必須有 v-if 或者 v-else-if
<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>

v-for

<view v-for="(item, index) in array">
 <text> {{idx}}: {{itemName.message}}</text>
</view>

v-model

父組件

<view><text>v-model的使用</text></view>
<input type="text" v-model="modelValueTest" />
<text>{{modelValueTest}}</text>

<comp v-model="modelValueTest2"></comp>
<view><text>組件使其改變{{modelValueTest2}}</text></view>

子組件

<template>
  <view>
    <input type="text" :value="value" @input="handleInput" />
  </view>
</template>

<script>

methods = {
    handleInput(e){
      console.log('input',e);
      this.$cmlEmit('input', {
        value:  Date.now()
      })
    }
  }
}
</script>

v-text

<view v-text="message"></view>

不支持組件的 v-text

v-show

<view v-show="elementShow">
    <text>測試元素c-show</text>
  </view>
<view><text>組件v-show</text></view>
<comp v-show="elementShow"></comp>
  • 使用 v-show 的元素不支持 同時(shí)有 style 屬性
  • elementShow 是來自 data 或者 computed 中的 key 值,或者 true/false

動(dòng)態(tài)組件

component 接受兩個(gè)屬性

屬性名說明
is接受一個(gè)計(jì)算屬性作為動(dòng)態(tài)渲染的標(biāo)簽名
shrinkcomponents接受 usingComponents 中的key值組成的字符串作為動(dòng)態(tài)組件選擇的范圍
<template>
  <view class="page-container">
    <view v-on: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"
    v-on:upcaseEvent="handleUpcaseEvent"
    :id="id"
    ></component>

Bug & Tips

注意 : 小程序端是通過條件判斷來模擬 component is 的效果的,所以不要在 component 標(biāo)簽上在在寫 c-if c-else c-else-if 等條件判斷

樣式語法

class 屬性

如果使用 class 語法,支持如下寫法

<template lang="vue">
<view class="page-container">
  <view><text :class="true? 'bg-green':''" class="font" >fafafa</text></view>
  <view><text class="bg-green font" >fafafa</text></view>
</view>
</template>

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

<template>
  <view>
    <text :class="prefix + 'a'">class數(shù)據(jù)綁定</text>
  </view>
</template>
<script>
class Index {
  data() {
    return {
      prefix: 'cls',
    };
  }
}
export default new Index();
</script>

三元運(yùn)算符

<view class="static" class="open ? 'cls1 cls2' : 'cls3 cls4'"> </view>

或者將其放入計(jì)算屬性

<template>
  <view class="itemClass"> </view>
</template>
<script>
class Index {
  computed = {
    itemClass() {
      return open ? 'cls1 cls2' : 'cls3 cls4';
    },
  };
}
export default new Index();
</script>

style 語法

如果使用 style 語法支持如下寫法,style 不支持多個(gè) style,即 style :style 同時(shí)寫

<view> <text style="background-color:red">fafafa</text></view>
<view><text :style="computedString">fafafa</text> </view>
<script>
class Index {
  data = {
    inlineStyle: 'border: 1px solid red;',
  };
  computed = {
    computedString() {
      return inlineStyle;
    },
  };
}
export default new Index();
</script>


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號