遷移 Weex 項(xiàng)目到 CML

2020-05-14 14:20 更新

遷移原則:

以小邏輯塊為單位,對(duì)照老代碼,以 cml 語(yǔ)法重寫,報(bào)錯(cuò)可修正

這樣可避免以下問(wèn)題:

1、大塊邏輯遷移會(huì)導(dǎo)致報(bào)錯(cuò)無(wú)法追查

2、直接 copy 會(huì)導(dǎo)致語(yǔ)法隱藏 bug 不可控(雖然 ide 沒有問(wèn)題,但真機(jī)調(diào)試出問(wèn)題)

請(qǐng)盡量按照 cml 語(yǔ)法或者類 vue 語(yǔ)法重寫遷移,避免語(yǔ)法糾錯(cuò)浪費(fèi)時(shí)間

項(xiàng)目初始化

cml init project

初始化后,CML 項(xiàng)目如下:

依具體情況配置構(gòu)建平臺(tái)和配置平臺(tái)基礎(chǔ)樣式。

可修改 chameleon.config.js 的 platforms 和 baseStyle 字段,如下:

假設(shè)有下面 ???? 結(jié)構(gòu)的 Weex 項(xiàng)目 weex-toolkit生成。

components下包含各個(gè)組件代碼,router.js下是路由配置,config是 Weex 項(xiàng)目的 webpack 構(gòu)建的基本配置

工程層面的遷移

遷移 —— webpack 配置

CML 的工程配置具體

CML 命令行工具,提供了 dev build 兩種構(gòu)建模式,可以對(duì)應(yīng)到 Weex 項(xiàng)目中的dev build
Weex 項(xiàng)目CML 項(xiàng)目
npm run devcml dev
npm run buildcml build
CML 內(nèi)置了對(duì)于 webpack 和項(xiàng)目的構(gòu)建

遷移 —— store

CML 項(xiàng)目中的 store 和 Weex 項(xiàng)目中的 store 文件下是對(duì)應(yīng)的。

假設(shè) vue 項(xiàng)目中某個(gè)組件

import { mapState } from 'vuex';
export default {
  computed: mapState(['count']),
};

那么在 CML 項(xiàng)目中

import store from '../path/to/store';

class Index {
  computed = store.mapState(['count']);
}
export default new Index();

#遷移 —— router

#router-view出口的對(duì)應(yīng)關(guān)系

假如 Weex 項(xiàng)目中入口文件 src/index.vue

<template>
  <div id="app">
    <router-view />
  </div>
</template>

那么對(duì)應(yīng)著 CML 項(xiàng)目中的src/app/app.cml,這里的<app>會(huì)渲染成<router-view>對(duì)應(yīng)的某個(gè)路由;

<template>
  <app store="{{store}}" router-config="{{routerConfig}}"></app>
</template>
#路由配置的對(duì)應(yīng)關(guān)系

weex項(xiàng)目中的路由 src/router.js

import Vue from 'vue';
import Router from 'vue-router';
import HelloWorld from '@/components/HelloWorld';

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/helloworld',
      name: 'HelloWorld',
      component: HelloWorld,
    },
  ],
});

cml項(xiàng)目中 src/router.config.json

{
  "mode": "history",
  "domain": "https://www.chameleon.com",
  "routes":[
    {
      "url": "/helloworld",
      "path": "/pages/HelloWorld/HelloWorld",
      "name": "helloworld",
      "mock": "index.php"
    }
  ]
}

其中:

url字段 對(duì)應(yīng) vue 中的path字段;

path字段對(duì)應(yīng) vue 中 import Comp from '/path/to/Comp'中的組件路徑

chameleon 會(huì)自動(dòng)引入 component 字段配置的組件,不需要再配置 component 字段;

總結(jié)

1 注意 CML 項(xiàng)目中不支持路由嵌套,如果有路由嵌套的情況需要考慮轉(zhuǎn)化成組件去實(shí)現(xiàn)

2 在遷移路由的時(shí)候,要一個(gè)一個(gè)路由對(duì)應(yīng)著去遷移

3 vue 項(xiàng)目中的一級(jí)路由的組件都通過(guò) cml init page 去初始化這個(gè)組件

遷移頁(yè)面/組件

假如 Weex 項(xiàng)目中 src/components/HelloWorld.vue組件內(nèi)有個(gè)子組件 comp;

首先我們修改下這兩個(gè)組件,使其有一些簡(jiǎn)單的新增 todolist 的功能

HelloWorld.vue

<template>
  <div class="demo-com">
    <div class="title">this is helloworld</div>
    <comp @parentClick="handleParentClick"></comp>
  </div>
</template>

<script>
import lodash from 'lodash';
import comp from './comp.vue';
export default {
  name: 'HelloWorld',
  data() {
    return {};
  },
  methods: {
    handleParentClick(...args) {
      console.log('parentClick', ...args);
    },
  },
  components: {
    comp,
  },
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.demo-com {
  display: flex;
  flex-direction: column;
  align-items: center;
  height: 400px;
  justify-content: center;
}
.title {
  align-self: center;
  color: #61c7fc;
  font-size: 72px;
  margin-bottom: 20px;
}
</style>

注意:如果第三方倉(cāng)庫(kù)中的某些 API 依賴該平臺(tái)的全局變量,那么這些 API 只能在該平臺(tái)使用,在其他平臺(tái)是無(wú)效的;

comp.vue

<template>
  <div>
    <input type="text" v-model="todo" />
    <div v-for="(item, index) in todos">
      {{ item }}
    </div>
    <div @click="addTodo">addTodo</div>
    <div @click="handleClick">觸發(fā)父組件事件</div>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data() {
    return {
      todo: 'todo1',
      todos: [],
    };
  },
  methods: {
    addTodo() {
      this.todos.push(this.todo);
    },
    handleClick() {
      console.log('click');
      this.$emit('parentClick', {
        value: 1,
      });
    },
  },
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>

新建頁(yè)面/組件

cml init page

輸入 HelloWorld

利用命令行命令,在src/pages中生成對(duì)應(yīng)的頁(yè)面

<template>
  <view><text>HelloCML</text></view>
</template>

<script>
class HelloWorld {
  //...
}

export default new HelloWorld();
</script>

<style></style>

<script cml-type="json">
{
  "base": {
    "usingComponents": {}
  },
  "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>
cml init component
選擇 Normal component
輸入 comp

生成的組件如下

<template>
  <view><text>HelloCML</text></view>
</template>

<script>
class Comp {
  //...
}

export default new Comp();
</script>
<style></style>
<script cml-type="json">
{
  "base": {
    "usingComponents": {}
  }
}
</script>

遷移組件引用

假設(shè) Weex 項(xiàng)目src/components/HelloWorld.vue中引用了其他組件 import comp from './comp.vue';

對(duì)應(yīng)到 CML 項(xiàng)目 組件需要在 usingComponents 引用,不需要在配置 components字段

修改src/pages/HelloWorld/HelloWorld.cml 頁(yè)面配置,如下:

<script cml-type="json">
{
  "base": {
    "usingComponents": {
      "comp":"/components/comp/comp"
    }
  }
}
</script>

總結(jié):

1 router.js中對(duì)應(yīng)的組件需要通過(guò) cml init page生成,然后在 router.config.js中配置對(duì)應(yīng)路由

2 組件內(nèi)部引用的子組件要通過(guò)cml init component生成,然后通過(guò) usingComponents字段去引用

3 組件內(nèi)引用的其他 js 庫(kù),比如import lodash from 'lodash'仍然通過(guò)import的形式引用

頁(yè)面&&組件遷移細(xì)節(jié)

template 模板遷移

這里以 CML 的 Vue 語(yǔ)法

數(shù)據(jù)綁定、條件渲染、循環(huán)、事件綁定的遷移

假設(shè),原有 vue 項(xiàng)目代碼,如下:

<div class="scroller-wrap">
  數(shù)據(jù)綁定
  <div>{{}}</div>
  條件渲染
  <div v-if="condition1">v-if</div>
  <div v-else-if="condition2">v-else-if</div>
  <div v-else>v-else</div>
  循環(huán)
  <div v-for="(item ,index) in array"></div>
  事件綁定
  <div id="tapTest" @click="handleClick">Click me!</div>
</div>

那么,使用 CML 的類 Vue 語(yǔ)法后:整體基本上不用變,只需要將標(biāo)簽改成 CML 的內(nèi)置標(biāo)簽即可。

<view class="scroller-wrap">
  數(shù)據(jù)綁定
  <view>{{}}</view>
  條件渲染
  <view v-if="condition">v-if</view>
  <view v-else-if="condition1">v-else-if</view>
  <view v-else>v-else</view>
  循環(huán)
  <view v-for="(item ,index) in array"></view>
  事件綁定
  <view id="tapTest" @click="handleClick">Click me!</view>
</view>

CML 對(duì)于語(yǔ)法的擴(kuò)展支持

指令的擴(kuò)展 c-show、c-model、c-show
component is 動(dòng)態(tài)組件的擴(kuò)展
事件綁定支持內(nèi)聯(lián)事件傳參數(shù)

Weex 的內(nèi)置組件遷移

以下表格列出 Weex 的內(nèi)置組件遷移到 CML 項(xiàng)目中的對(duì)應(yīng)情況,不能在視圖層用 Weex 端特有的組件,需要通過(guò)以下標(biāo)簽進(jìn)行替換

除非是通過(guò)多態(tài)組件調(diào)用的下層組件才可以使用。

對(duì)于 Weex 內(nèi)置的組件,CML 提供了大部分與之對(duì)應(yīng)的可以跨端的組件。

Weex 內(nèi)置組件CML備注
<div><view>支持跨多端
<text><text>支持跨多端
<image><image>支持跨多端
<list><list>支持跨多端
<cell><cell>支持跨多端
<loading><c-loading>支持跨多端
<scroller><scroller>支持跨多端
<slider><carousel>對(duì)于輪播圖組件,chameleon 內(nèi)置了carousel組件,如果想要用原生的slider,需要在多態(tài)組件中通過(guò) origin-slider使用
<textarea><textarea>支持跨多端
<input><input>支持跨多端
<video><video>支持跨多端

chameleon 不支持的 Weex 內(nèi)置組件

Weex 內(nèi)置組件在 CML 中的替換方式
<a>可以通過(guò)給一個(gè) text 標(biāo)簽綁定事件,通過(guò) chameleon-api 提供的接口打開頁(yè)面
<waterfall>該組件不支持跨多端,僅可在多態(tài)組件中使用
<web>該組件不支持跨端,僅可在多態(tài)組件中使用
<richtext>該組件不支持跨端,僅可在多態(tài)組件中使用

根據(jù)以上教程,我們可以遷移HelloWorld.vue和comp.vue中的模板內(nèi)容了

HelloWorld.cml

<template lang="vue">
  <view>
    <text>this is helloworld</text>
    <comp @parentClick="handleParentClick"></comp>
  </view>
</template>

comp.cml

<template lang='vue'>
  <view>
    <input type="text" v-model="todo" ></input>
    <div v-for="(item,index) in todos">
      {{item}}
    </div>
    <div @click="addTodo">addTodo</div>
    <view @click="handleClick"><text>觸發(fā)父組件事件</text></view>
  </view>
</template>

JS 內(nèi)容遷移

生命周期遷移 :和 vue 保持一致

數(shù)據(jù)的遷移

Weex 項(xiàng)目 API 的遷移

API 遷移包括 http 請(qǐng)求 路由跳轉(zhuǎn) 本地存儲(chǔ)等 


不能在邏輯層用 Weex 端特有的內(nèi)置模塊,需要通過(guò)以下chameleon-api提供的進(jìn)行替換

除非是通過(guò)多態(tài)組件調(diào)用的下層組件才可以直接使用。

WeexCML備注
animationchameleon-api 中的 createAnimation參考
cliboardchameleon-api 中的 clipBoard參考
domchameleon-api 中的 getRect參考
globalEvent暫不支持
metachameleon-api 中的 getSystemInfo參考:可以通過(guò)這個(gè) API 獲取到視口的值然后給頁(yè)面寬高賦值
modalchameleon-api 中的 showToast參考
navigatorchameleon-api 中的 路由導(dǎo)航參考
picker擴(kuò)展組件中的 c-picker參考
storagechameleon-api 中的數(shù)據(jù)存儲(chǔ)參考
streamchameleon-api 中的網(wǎng)絡(luò)請(qǐng)求參考
webview暫不支持
websocketschameleon-api 中的 websockets參考

事件的觸發(fā)機(jī)制,映射如下:

vue 項(xiàng)目cml
this.$emit(xxx,xxx)this.$cmlEmit(xxx,xxx)
事件對(duì)象參數(shù)

CML 對(duì) web native wx 各個(gè)端的事件對(duì)象進(jìn)行了統(tǒng)一代理參考。

對(duì)于灰度區(qū)組件(多態(tài)組件)各個(gè)端的事件對(duì)象還是對(duì)應(yīng)端的事件對(duì)象,CML 框架不會(huì)對(duì)灰度區(qū)origin-開頭的標(biāo)簽和第三方組件標(biāo)簽上綁定的事件進(jìn)行事件代理

CML 支持的類 Vue 語(yǔ)法,只有在文檔中列出的語(yǔ)法才支持多端,其他沒有列出的語(yǔ)法僅可以在 Web 端使用,跨端沒有支持,比如 v-html class 的對(duì)象語(yǔ)法 數(shù)組語(yǔ)法等。

不支持的事件

longpress appear disappear 事件暫不支持;

事件冒泡

chameleon 生成的 Weex 項(xiàng)目默認(rèn)都是開啟了支持事件冒泡的機(jī)制

同時(shí)擴(kuò)展了阻止事件冒泡的語(yǔ)法;

vue 語(yǔ)法(僅僅支持 .stop)

<view @click.stop="handleClick"></view>

cml 語(yǔ)法

<view c-catch:click="handleClick"></view>

總結(jié)

1 由于 CML 是跨多端的框架,所以在 Weex 端特有的環(huán)境變量,比如weex.config等在 CML 中是不支持的

2 對(duì)于 Weex 的內(nèi)置模塊,比如 animation 等,在 chameleon-api 中基本上都有對(duì)應(yīng),參考上文 Weex 內(nèi)置模塊的遷移

根據(jù)以上教程,我們可以遷移HelloWorld.vue和comp.vue中的 js 內(nèi)容了

HelloWorld.cml

<template lang="vue">
  <view>
    <text>this is helloworld</text>
    <comp @parentClick="handleParentClick"></comp>
  </view>
</template>

<script>
import lodash from 'lodash';
class HelloWorld {
  methods = {
    handleParentClick(...args) {
      console.log('parentClick', ...args);
    },
  };
}

export default new HelloWorld();
</script>

comp.cml

<script>
class Comp {
  data = {
    todo: 'todo1',
    todos: [],
  };

  methods = {
    addTodo() {
      this.todos.push(this.todo);
    },
    handleClick() {
      this.$cmlEmit('parentClick', {
        value: 1,
      });
    },
  };
}

export default new Comp();
</script>

style 內(nèi)容的遷移

weex 樣式官方文檔

頁(yè)面布局的遷移

使用 flexbox進(jìn)行樣式布局

關(guān)于樣式的使用教程

模板上的樣式語(yǔ)法

Vue 樣式語(yǔ)法規(guī)范

樣式單位的遷移

如果樣式想要適配多端,需要將單位改成cpx;

根據(jù)以上教程,我們可以遷移HelloWorld.vue和comp.vue中的 js 內(nèi)容了

HelloWorld.cml

.demo-com { display: flex; flex-direction: column; align-items: center; height:400cpx;
justify-content: center; } .title { align-self: center; color: #61c7fc; font-size: 72cpx;
margin-bottom: 20cpx; }


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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)