Chameleon:原來寫一個跨多端項目,能夠這麼容易!

出品 | 滴滴技術php

做者 | 許國棟css


▍前言:隨着各種小程序的百花齊放,業務對跨多端的需求愈來愈明顯。雖然各端環境變幻無窮,不管各種小程序、Weex、React-Native、Flutter、快應用,它們萬變不離其宗的是 MVVM 架構設計思想。今天,給你們帶來 Chameleon 遷移指南,一套代碼完成各端需求,滿滿乾貨~html

cml做爲真正讓一套代碼運行多端的框架,提供標準的 MVVM 模式,統一開發各種終端。同時,擁有各端獨立的運行時框架 (runtime)、數據管理 (store)、組件庫 (ui)、接口 (api)。此外,cml在跨端能力增強、能力統1、表現一致等方面作了許多工做。
前端

今天,爲了讓你們的項目優雅升級,快速接入,給你帶來一份豐盛的 cml 遷移指南。vue

視頻教程源碼地址github.com/jalonjs/cml…
node

視頻教程地址:sfwb.didistatic.com/static/wb/5…webpack



閱讀索引git

  • 目錄結構github

  • 如何修改配置web

  • 如何使用路由能力

  • 如何註冊

  • 如何聲明生命週期

  • 數據如何響應到視圖

  • 事件交互

  • 佈局與外觀

  • 自定義組件

  • 如何實現父子組件事件通訊

  • 組件使用總結

  • 如何調用平臺接口能力

  • 遷移實例


▍目錄結構

和微信小程序同樣,cml 包含一個描述總體程序的 app 和多個描述各自頁面的 page

▍小程序目錄結構

1.
2├── components // 包含各個組件
3├── pages // 包含各個頁面
4├── app.js // 包含各個組件
5├── app.js  // 應用啓動入口
6├── app.json // 全局配置
7├── app.wxss // 全局樣式
8└── project.config.json // 項目配置文件
複製代碼

▍cml目錄結構

1.
 2├── dist // 各個端構建結果
 3│   ├── alipay 
 4│   ├── baidu 
 5│   ├── wx 
 6│   ├── web  
 7│   ├── weex 
 8│   └── config.json // 跨端配置map映射表
 9├── node_modules // 第三方庫
10├── mock // 模擬 接口數據 和 模板數據
11├── src  // 源代碼開發目錄
12│   ├── app // 應用啓動入口
13│   ├── assets // 靜態資源
14│   ├── components // 包含組件
15│   ├── pages  // 包含頁面
16│   ├── store //數據管理
17│   └── router.config.json // 路由配置文件
18├── chameleon.config.js // 項目配置文件
19└── package.json // npm包配置文件
複製代碼

▍如何修改配置

在小程序項目裏面,分爲:

▍小程序 — 項目配置

能夠在項目根目錄使用 project.config.json 文件對項目進行配置。

配置示例:

1{
2  "miniprogramRoot": "./src",
3  "debugOptions": {}
4}
複製代碼

▍小程序 — 全局配置

小程序根目錄下的 app.json 文件用來對微信小程序進行全局配置,決定頁面文件的路徑、窗口表現、設置網絡超時時間、設置多 tab 等

配置示例:

1 {
 2  "pages": ["pages/index/index", "pages/logs/index"],
 3  "window": {
 4    "navigationBarTitleText": "Demo"
 5  },
 6  "networkTimeout": {
 7    "request": 10000,
 8    "downloadFile": 10000
 9  }
10}
複製代碼

▍小程序 — 頁面配置

每個小程序頁面也可使用 .json 文件來對本頁面的窗口表現進行配置。

頁面的配置只能設置 app.json 中部分 window 配置項的內容,頁面中配置項會覆蓋 app.jsonwindow 中相同的配置項。

配置示例:

1{
2  "navigationBarBackgroundColor": "#ffffff",
3  "navigationBarTextStyle": "black",
4  "navigationBarTitleText": "微信接口功能演示",
5  "backgroundColor": "#eeeeee",
6  "backgroundTextStyle": "light"
7}
複製代碼

一樣,在 cml項目裏面,分爲如下幾種配置方案:

▍cml — 項目配置

chameleon.config.js 爲項目的配置文件,你能夠定製化構建,好比是否帶hash,是否壓縮等等。

配置示例:

1 // 設置靜態資源的線上路徑
2 const publicPath = '//www.static.chameleon.com/static';
3 // 設置api請求前綴
4 const apiPrefix = 'https://api.chameleon.com';
5 // 合併配置
6 cml.config.merge({
7   wx: {
8    build: {apiPrefix}
9  },
10  alipay: {
11    build: {apiPrefix}
12  },
13  baidu: {
14    build: {apiPrefix}
15  },
16  web: {
17    dev: {
18      hot: true,
19      console: true
20    },
21    build: {
22      publicPath: `${publicPath}/web`,
23      apiPrefix
24    }
25  },
26  weex: {
27    build: {
28      publicPath: `${publicPath}/weex`,
29      apiPrefix
30    }
31  }
32})
複製代碼

▍cml — 全局設置

cml 項目 app 目錄下的 app.cml 文件的 <script cml-type="json" /> 用來對 cml應用 進行全局配置,具備 跨端配置 和 差別化 的能力。

配置示例:

1<script cml-type="json">
 2{
 3  "base": {
 4    "window": {
 5      "navigationBarTitleText": "各個端共同title",
 6    },
 7    "permission": {
 8      "scope.userLocation": {
 9        "desc": "你的位置信息將用於小程序位置接口的效果展現"
10      }
11    }
12  },
13  "wx": {
14    "window": {
15      "backgroundTextStyle":"light",
16      "navigationBarBackgroundColor": "#fff",
17      "navigationBarTitleText": "差別化 title",
18      "navigationBarTextStyle":"black"
19    }
20  },
21  "baidu": {
22    "window": {
23      "backgroundTextStyle": "light"
24    }
25  },
26  "alipay": {
27      "window": {
28        "defaultTitle": "Chameleon"
29      }
30  }
31}
32</script>
複製代碼

▍cml — 頁面 / 組件配置

經過 usingComponents 配置 組件路徑 註冊引用的組件。

配置示例:

1  <script cml-type="json">
 2  {
 3  "base": {
 4    "usingComponents": {
 5      "navi": "/components/navi/navi",
 6      "navi-npm": "cml-test-ui/navi/navi"
 7    }
 8  },
 9  "wx": {
10  },
11  "alipay": {
12  },
13  "baidu": {
14  },
15  "web": {
16  },
17  "weex": {
18  }
19}
20</script>
複製代碼

▍如何使用路由能力

▍小程序配置路由

app.json 配置項列表的 pages 字段用於指定小程序由哪些頁面組成,每一項都對應一個頁面的 路徑+文件名 信息。

數組的第一項表明小程序的初始頁面(首頁)。新增/減小頁面,須要對 pages 數組進行修改。

若是項目有 pages/index/index.wxmlpages/logs/logs.wxml 兩個頁面,則須要在 app.json 中寫。

1{
2  "pages": ["pages/index/index", "pages/logs/logs"]
3}
複製代碼

▍cml 配置路由

src/router.config.json 是路由的配置文件,cml 內置了一套各端統一的路由管理方式。相應有 cml 路由配置映射以下:

1   {
 2  "mode": "history",
 3  "domain": "https://www.chameleon.com",
 4  "routes":[
 5    {
 6      "url": "/cml/h5/index",
 7      "path": "/pages/index/index",
 8      "mock": "index.php"
 9    },
10    {
11      "url": "/cml/h5/logs",
12      "path": "pages/logs/logs",
13      "mock": "logs.php"
14    }
15  ]
16}
複製代碼

文件名不須要寫文件後綴,cml框架會自動去尋找對於位置的 .cml 文件進行處理。

▍小程序使用路由

▍cml 使用路由

依據統一資源索引URI,自適應打開不一樣環境同一路由PATH:

▍如何註冊

▍小程序註冊應用

在小程序項目裏面,App() 函數用來註冊一個小程序。接受一個 Object 參數,其指定小程序的生命週期回調等。

示例代碼:

1 App({
2  onLaunch(options) {
3    // Do something initial when launch.
4  },
5  globalData: 'I am global data'
6})
複製代碼

▍cml 註冊應用

示例代碼:

1 <script>
 2 import store from '../store/index.js'
 3 import routerConfig from '../router.config.json';
 4
 5 class App {
 6  data = {
 7    store,
 8    routerConfig
 9  }
10  created(res) {
11  }
12 }
13
14 export default new App();
15 </script>
複製代碼

細心的你會發現,小程序中app.json app.js app.wxsssrc/app/app.cml的對應關係以下:


▍小程序註冊頁面

在小程序項目裏面,Page(Object) 函數用來註冊一個頁面。接受一個 Object 類型參數,其指定頁面的初始數據、生命週期回調、事件處理函數等。

示例代碼:

1 // index.js
 2 Page({
 3  data: {
 4    text: 'This is page data.'
 5  },
 6  changeText: function(e) {
 7    // sent data change to view
 8    this.setData({
 9      text: 'CML'
10    })
11  }
12})
複製代碼

▍cml 註冊頁面

示例代碼:

1 <script>
 2 class Index {
 3  data = {
 4    text: 'Chameleon'
 5  }
 6  methods = {
 7    changeText: function(e) {
 8      // sent data change to view
 9      this.text = 'CML';
10    }
11  }
12  computed = {}
13  watch = {}
14 };
15 export default new Index();
16 </script>
複製代碼

▍小程序註冊組件

在小程序項目裏面,

Component(Object) 構造器可用於定義組件,調用 Component 構造器時能夠指定組件的屬性、數據、方法等。

示例代碼:

1 Component({
 2  properties: {
 3    myProperty: { // 屬性名
 4      type: String, // 類型(必填)
 5      value: '' // 屬性初始值(可選)
 6    },
 7    myProperty2: String // 簡化的定義方式
 8  },
 9  data: {
10    text: ''
11  }, // 私有數據,可用於模板渲染
12
13  // 生命週期函數,能夠爲函數,或一個在methods段中定義的方法名
14  attached() { }, 
15  ready() { },
16  methods: {
17    onMyButtonTap() {
18      this.setData({
19        // 更新屬性和數據的方法與更新頁面數據的方法相似
20        text: 'wx'
21      })
22    }
23  }
24})
複製代碼

▍cml 註冊組件

示例代碼:

1 <script>
 2 class MyComponent {
 3  props = {
 4    myProperty: { // 屬性名
 5      type: String, // 類型(必填)
 6      default: '' // 屬性初始值(可選)
 7    },
 8    myProperty2: String // 簡化的定義方式
 9  }
10  data =  {
11    text: ''
12  } // 私有數據,可用於模板渲染
13
14  beforeMount() {}
15  mounted() {}
16  methods = {
17    onMyButtonTap() {
18      this.text = 'cml'
19    }
20  }
21  computed = {}
22  watch = {}
23 };
24 export default new MyComponent();
25 </script>
複製代碼

▍如何聲明生命週期

統一各端應用生命週期的定義,是跨端框架的重要組成,也是遷移的必經之路。

▍小程序聲明生命週期

能夠在 App(Object)Page(Object)Component(Object) 傳入Object參數,其指定小程序的生命週期回調等。

代碼示例:

1 // index.js
 2 Page({
 3  onLoad(options) {
 4    // Do some initialize when page load.
 5  },
 6  onReady() {
 7    // Do something when page ready.
 8  },
 9  onShow() {
10    // Do something when page show.
11  },
12  onHide() {
13    // Do something when page hide.
14  },
15  onUnload() {
16    // Do something when page close.
17  },
18  onShareAppMessage() {
19    // return custom share data when user share.
20  }
21})
複製代碼

▍cml 聲明生命週期

.cml 文件 <script /> 代碼塊返回的對象實例,其指定生命週期回調。

示例代碼:

1 <script>
 2 class Index {
 3  beforeCreate(query) {
 4    // data數據掛載到this根節點上以前,以及methods全部方法掛載到實例根節點以前
 5    // 注意:只用頁面的 beforeCreate鉤子 會返回頁面query
 6    console.log('App beforeCreate: 打開當前頁面路徑中的參數是 ', query)
 7  }
 8  created() {
 9    // data,methods裏面的這些events掛載完成
10    console.log('App created')
11  }
12  beforeMount() {
13    // 開始掛載已經編譯完成的cml到對應的節點時
14    console.log('App beforeMount')
15  }
16  mounted() {
17    // cml模板編譯完成,且渲染到dom中完成,在整個生命週期中只執行一次
18    console.log('App mounted')
19  }
20  beforeDestroy() {
21    // 實例銷燬前
22    console.log('App beforeDestroy')
23  }
24  destroyed() {
25    // 實例銷燬後
26    console.log('App destroyed')
27  }
28 };
29 export default new Index();
30 </script>
複製代碼

▍App 生命週期映射

小程序 app.js中的生命週期 -> cml src/app/app.cml

▍Page 生命週期映射

小程序 Page()中的生命週期 -> cml src/pages/mypage/mypage.cml

  1. 小程序                                                            chameleon
  2. onLoad                                                           beforeCreate
  3. onShow                                                          mounted
  4. onUnload                                                       destroyed
  5. onReady                                                         生命週期多態
  6. onHide                                                            生命週期多態
  7. onShareAppMessage                                    生命週期多態

▍Component 生命週期映射

小程序 Component()中的生命週期 -> cml src/components/mycomponent/mycomponent.cml


▍生命週期總結

每一個 cml 實例( AppPageComponent )在被建立時都要通過一系列的初始化過程。

例如,須要設置數據監聽、編譯模板、將實例掛載到 CML節點 並在數據變化時更新 CML節點 等。同時在這個過程當中也會運行一些叫作生命週期鉤子的函數,這給開發者在不一樣階段添加本身的代碼的機會。

cmlApp頁面 Page組件 Component 提供了一系列生命週期事件,保障應用有序執行。

另外,若是你想使用某個端特定的生命週期,你能夠從業務出發使用 生命週期多態

▍數據如何響應到視圖

現在,雙向數據綁定&單向數據流 已深刻開發者平常,MVMM開發模式算是框架標配。

數據綁定條件渲染列表渲染是如何書寫的呢?

示例代碼:

▍小程序使用數據響應用


▍cml 使用數據響應

1 <template>
 2 <!--index.cml-->
 3 <view class="scroller-wrap">
 4    <!--數據綁定-->
 5  <view>{{message}}</view>
 6  <!--條件渲染-->
 7  <view c-if="{{view == 'WEBVIEW'}}">WEBVIEW</view>
 8  <view c-else-if="{{view == 'APP'}}">APP</view>
 9  <view c-else="{{view == 'MINA'}}">MINA</view>
10    <!--列表渲染-->
11  <view c-for="{{array}}" c-for-index="index" c-for-item="item">{{item}}</view>
12 </view>
13 </template>
14 <script>
15 class Index {
16  data =  {
17    message: 'Hello MINA!',
18    view: 'MINA',
19    array: [1, 2, 3, 4, 5]
20  }
21
22  beforeCreate () {
23    this.message = 'cml'
24  }
25 };
26 export default new Index();
27 </script>
複製代碼

▍數據響應總結

cml運行時框架 提供了跨端響應式數據綁定系統(Data binding),當作數據修改的時候,只須要在邏輯層修改數據,視圖層就會作相應的更新。

只須要將 view<-->model 交互部分邏輯,做簡單遷移,即可使它成爲跨多端的數據響應系統。

▍事件交互

cml 支持一些基礎的事件,保障各端效果(類型綁定事件對象)一致運行。

示例代碼:

▍小程序使用事件

1<!--wxml-->
2<view id="tapTest" data-hi="WeChat" bindtap="tapName">Click me!</view>
複製代碼

1// page.js
2Page({
3  tapName(event) {
4    console.log(event)
5  }
6})
複製代碼

▍cml 使用事件

1 <template>
 2  <view id="tapTest" data-hi="WeChat" c-bind:tap="tapName">
 3    <text>Click me!</text>
 4  </view>
 5 </template>
 6 <script>
 7 class Index {
 8  methods = {
 9    tapName(e) {
10      // 打印事件對象
11      console.log('事件對象:', e);
12    }
13  }
14}
15 export default new Index();
16 </script>
複製代碼

▍事件使用總結

同時,還支持自定義事件,用於父子組件之間的通訊。

另外,若是你想要使用某個端特定的事件,cml 並不會限制你的自由發揮,你能夠從業務出發使用 組件多態 或者 接口多態 差別化實現功能。

▍佈局與外觀

各端描述 佈局和外觀 的層疊樣式表(CSS)實現存在差別,包括不限於 佈局、盒模型、定位、文本。

因此, cml 框架內置跨端一致性基礎樣式能力。

而且,定義了用於描述頁面的樣式規範CMSS(Chameleon Style Sheet)

▍如何導入外部樣式

使用 @import 語句能夠導入外聯樣式表,@import 後跟須要導入的外聯樣式表的相對路徑,用 ; 表示語句結束。

▍小程序導入外部樣式

示例代碼:


▍cml 導入外部樣式

詳細文檔

示例代碼:


▍樣式使用總結

同時,爲了統一多端尺寸單位,呈現效果一致,同時頁面響應式佈局,cml 項目統一採用 cpx 做爲尺寸單位,規定以屏幕750px(佔滿屏幕)視覺稿做爲標準。

並且,各端樣式表擁有的能力 不盡相同,是項目遷移的主要陣地之一。

另外,若是你想要使用某個端特定的樣式能力,cml 並不會限制你的自由發揮,你能夠從業務出發使用 樣式多態

注意:因爲chameleon應用是 跨多端web native 小程序框架,若是須要跨native,必須使用 flexbox 進行樣式佈局。

▍自定義組件

開發者能夠將頁面內的功能模塊抽象成自定義組件,以便在不一樣的頁面中重複使用。自定義組件在使用時與基礎組件很是類似。

▍小程序建立自定義組件

代碼示例:

1 Component({
 2  properties: {
 3    // 這裏定義了innerText屬性,屬性值能夠在組件使用時指定
 4    innerText: {
 5      type: String,
 6      value: 'default value',
 7    }
 8  },
 9  data: {
10    // 這裏是一些組件內部數據
11    someData: {}
12  },
13  methods: {
14    // 這裏是一個自定義方法
15    customMethod() {}
16  }
17})
複製代碼

▍cml 建立自定義組件

示例代碼:

1 <script>
 2 class MyComponent {
 3  props = {
 4    // 這裏定義了innerText屬性,屬性值能夠在組件使用時指定
 5    innerText: {
 6      type: String,
 7      value: 'default value',
 8    }
 9  }
10  data = {
11    // 這裏是一些組件內部數據
12    someData: {}
13  }
14  methods = {
15    // 這裏是一個自定義方法
16    customMethod() {}
17  }
18  computed = {}
19  watch = {}
20};
21export default new MyComponent();
22</script>
複製代碼

▍如何使用自定義組件

使用已註冊的自定義組件前,首先要進行引用聲明。此時須要提供每一個自定義組件的標籤名和對應的自定義組件文件路徑。

▍小程序使用自定義組件

代碼示例:

page.json 中進行引用聲明

1{
2  "usingComponents": {
3    "component-tag-name": "path/to/the/custom/component"
4  }
5}
複製代碼

page.wxml 中使用

1 <view>
2  <!-- 如下是對一個自定義組件的引用 -->
3  <component-tag-name inner-text="Some text"></component-tag-name>
4 </view>
複製代碼

▍cml 使用自定義組件

代碼示例:

page.cml<script cml-type='json' />進行引用聲明

1<script cml-type="json">
2{
3  "base": {
4      "usingComponents": {
5        "component-tag-name": "path/to/the/custom/component"
6      }
7  }
8}
9</script>
複製代碼

page.cml<template />使用

1<template>
2<view>
3  <!-- 如下是對一個自定義組件的引用 -->
4  <component-tag-name inner-text="Some text"></component-tag-name>
5</view>
6</template>
複製代碼

▍如何實現父子組件事件通訊

事件系統是組件間通訊的主要方式之一。自定義組件能夠觸發任意的事件,引用組件的頁面能夠監聽這些事件。

▍小程序組件通訊

代碼示例:


▍cml 組件通訊

代碼示例:


▍組件使用總結

和小程序同樣,cml框架 提供了大量內置組件擴展組件,抹平多端差別,便於開發者經過組合這些組件,建立出強大的應用程序。

擴展組件須要額外引入。如:

1<script cml-type="json">
2{
3  "base": {
4      "usingComponents": {
5        "c-dialog": "cml-ui/components/c-dialog/c-dialog"
6      }
7  }
8}
9</script>
複製代碼

在執行 cml build 構建打包時,cml 框架 會按需打包引用的內置組件和擴展組件,爲代碼瘦身。

內置組件擴展組件 都是支持跨多端的,對於一些沒有提供的某個端的組件,能夠經過組件多態來實現。

若是但願使用小程序端的原生組件,那麼能夠在原生標籤前加上 origin-*cml框架會渲染原生組件參考

注意:origin-* 只能在灰度區文件中使用。

如在 map.wx.cml 文件中使用原生地圖組件 <map/>

1 <!-- map.wx.cml -->
 2 <template>
 3  <origin-map
 4    id="map"
 5    longitude="113.324520"
 6    latitude="23.099994"
 7    controls="{{controls}}"
 8    bindcontroltap="controltap"
 9    style="width: 100%; height: 300px;"
10  ></origin-map>
11 </template>
複製代碼

▍組件如何調用平臺接口能力

在小程序裏面,能夠經過微信原生 API,調起如獲取用戶信息,本地存儲,支付功能等。

示例代碼:

1try {
2  wx.setStorageSync('name', 'Hanks')
3} catch (e) {
4  console.error(e)
5}
複製代碼

一樣,在 cml 項目裏面能夠這樣調用:

示例代碼:

1import cml from 'chameleon-api'
2cml.setStorage('name', 'Hanks').then((res)=>{
3  console.log(res)
4},function(e){
5  console.error(e)
6})
複製代碼

▍藉口使用總結

cml 框架提供了豐富的多態接口,能夠調起各端提供的原生能力,如系統信息、元素節點信息、動畫效果、本地存儲、網絡請求、地理位置等。請參考 API 文檔。

chameleon-api提供的接口都是支持跨多端的,對於一些沒有提供的某個端的原生接口,能夠經過接口多態來調用。

▍遷移實例

下面給出各端(vue、weex、小程序)遷移cml指南 以及 cml 導出組件到各端指南的具體遷移文檔:



點擊圖片瞭解更多:

有關安裝、使用過程以及常見問題解答,請查看如下連接:

GitHub:github.com/didi/chamel…

快速開始:cml.js.org/doc/quick_s…


同時歡迎加入「Chameleon 用戶交流羣」
請在滴滴技術公衆號後臺回覆「Chameleom」便可加入


▍END


                                    


                                                                               許 國 棟

                                                        滴滴 | 高級軟件開發工程師

Chameleon 成員,主要負責框架運行時、組件生態化等相關開發工做。喜歡專研前端技術,對領域前沿技術感興趣。有跨端相關的看法的同窗,歡迎來相互探討。

相關文章
相關標籤/搜索