遷移 Vue 項目到 CML

2020-05-14 14:20 更新

遷移原則:

以小邏輯塊為單位,對照老代碼,以 cml 語法重寫,報錯可修正

這樣可避免以下問題:

1、大塊邏輯遷移會導(dǎo)致報錯無法追查

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

請盡量按照 cml 語法或者類 vue 語法重寫遷移,避免語法糾錯浪費時間

項目初始化

cml init project

初始化后,CML 項目如下:

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

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

假設(shè)有下面 ???? 結(jié)構(gòu)的 vue 項目(vue-cli 2 版本生成的)

components 下包含各個組件代碼,router 下是路由配置,store 是數(shù)據(jù)管理中心,config 和 build 下是 vue 項目的 webpack 構(gòu)建的基本配置

接下來就一步步展示如何將這個項目遷移到 CML

工程層面的遷移

遷移 —— webpack 配置

CML 的工程配置具體

CML 命令行工具,提供了 dev build 兩種構(gòu)建模式,可以對應(yīng)到 Vue 項目中的 dev build

vue 項目CML 項目
npm run devcml dev
npm run buildcml build

chameleon 內(nèi)置了對于 webpack 和項目的構(gòu)建

遷移 —— store

CML 中的 store 

CML 項目中的store和 vue 項目中的store文件下是對應(yīng)的;

假設(shè) vue 項目中某個組件

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

那么在 CML 項目中

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

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

遷移 —— router

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

假設(shè)vue項目中入口文件 src/App.vue

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

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

<template>
  <app store="{{store}}" router-config="{{routerConfig}}"></app>
</template>

路由配置對應(yīng)關(guān)系

vue項目中的路由 src/router/index.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,
    },
  ],
});

對于router.js中配置的一級路由,需要通過 cml init page 去生成對應(yīng)的組件

cml項目中 src/router.config.json

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

其中:

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

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

chameleon 會自動引入 component 字段配置的組件,不需要再配置 component 字段;

總結(jié)

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

2 在遷移路由的時候,要一個一個路由對應(yīng)著去遷移

3 vue 項目中的一級路由的組件都通過 cml init page去初始化這個組件

遷移頁面/組件

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

首先我們修改下這兩個組件,使其有一些簡單的新增 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>

注意:如果第三方倉庫中的某些 API 依賴該平臺的全局變量,那么這些 API 只能在該平臺使用,在其他平臺是無效的;

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>

新建頁面/組件

cml init page

輸入 HelloWorld

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

<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

利用命令行命令,在src/components中生成對應(yīng)的組件

<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è) vue 項目src/components/HelloWorld.vue中引用了其他組件 import comp from './comp.vue';

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

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

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

總結(jié)

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

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

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

頁面&&組件遷移細節(jié)

template模板遷移

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

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

<div class="scroller-wrap">
  數(shù)據(jù)綁定
  <div>{{}}</div>
  條件渲染
  <div v-if="condition">v-if</div>
  <div v-else-if="condition1">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 語法后:整體基本上不用變,只需要將標(biāo)簽改成 CML 的內(nèi)置標(biāo)簽即可。

注意需要聲明<template lang="vue"></template>

<template lang="vue">
<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></template>

vue 項目標(biāo)簽 -> cml 標(biāo)簽

vue 項目cml
divview
text spantext
imgimage
inputinput組件
buttonbutton組件
textareatextarea組件
switchswitch組件
radioradio組件
checkboxcheckbox組件
imageimage組件
videovideo組件

沒有列出來的標(biāo)簽比如head p main等等只能在多態(tài)組件中使用,不支持跨多端

對于 a標(biāo)簽的 href,如果想要達到跨多端的效果,需要通過綁定事件使用 cml.open() 去跳轉(zhuǎn)。

CML 對于語法的擴展支持

指令的擴展 c-show、c-model、c-show

component is 動態(tài)組件的擴展

事件綁定支持內(nèi)聯(lián)事件傳參數(shù)

遷移注意點

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

根據(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ù)的遷移

vue 項目 API 的遷移

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

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

router.push({ path: '/pages/navigateBack/index' });

跨多端的路由僅支持 傳入 path 字段進行路由,不支持路由 name字段的路由

那么,使用 CML 語法后:

import cml from 'chameleon-api';
cml.redirectTo({
  path: '/pages/navigateBack/index',
});

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

vue 項目cml
this.$emit(xxx,xxx)this.$cmlEmit(xxx,xxx)

事件對象參數(shù)

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

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

事件冒泡

#chameleon 生成的 Weex 項目默認都是開啟了支持事件冒泡的機制

#同時擴展了阻止事件冒泡的語法;

vue 語法(僅僅支持 .stop)

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

cml 語法

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

總結(jié)

1 由于 CML 是跨多端框架,所以在 Web 端特有的全局變量,比如 window document history location等在 CML 中是不支持的

2 對于 vue 的一些全局 API 比如Vue.extend Vue.set以及一些文檔中沒有列出的指令,比如v-html v-pre等都是不支持跨多端的

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

HelloWorld.cml

<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)容的遷移

頁面布局的遷移

由于 CML 應(yīng)用是 跨多端 Web Native 小程序框架,如果需要跨 Native,必須使用 flexbox 進行樣式布局,其他場景可以參考只跨 Web 和小程序的應(yīng)用

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

模板上的樣式語法

樣式單位的遷移

如果樣式想要適配多端,需要將單位改成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)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號