codecamp

迁移微信小程序项目到 CML

迁移原则:

以小逻辑块为单位,对照老代码,以 cml 语法重写,报错可修正

这样可避免以下问题:

1、大块逻辑迁移会导致报错无法追查

2、直接 copy 会导致语法隐藏 bug 不可控(虽然 ide 没有问题,但真机调试出问题)

请尽量按照 cml 语法重写迁移,避免语法纠错浪费时间

小程序多文件结构 -> cml 单文件页面

小程序CML
xxx.wxml<template></template>
xxx.js<script></script>
xxx.wxss<style></style>
xxx.json<script cml-type="json"></script>

项目初始化

cml init project

初始化后,CML 项目如下:

依具体情况配置构建平台和配置平台基础样式。

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

假设有下面 ???? 结构的小程序项目

pages 下包含各个页面,components 下包含各个组件代码

迁移 app.js、app.json

小程序代码配置微信应用的配置

app.json

{
  "pages":[
    "pages/index1",
    "pages/index2",
    "pages/index3",
    "pages/index4",
  ],
  "window":{
    "backgroundTextStyle":"light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "WeChat",
    "navigationBarTextStyle":"black"
  }
}

迁移 app.json ———— 路由 pages 配置

以上小程序 app.json 中 pages 字段 -> src/router.config.json 中 path 字段

{
  "mode": "history",
  "domain": "https://www.chameleon.com",
  "routes":[
    {
      "url": "/cml/h5/index",
      "path": "/pages/index1/index1",
      "name": "首页",
      "mock": "index.php"
    },
    {
      "url": "/cml/h5/inner-detail",
      "path": "/pages/index2/index2",
      "name": "首页",
      "mock": "index.php"
    },
    {
      "url": "/cml/h5/inner-home",
      "path": "/pages/index3/index3",
      "name": "首页",
      "mock": "index.php"
    },
    {
      "url": "/cml/h5/inner-my",
      "path": "/pages/index4/index4",
      "name": "首页",
      "mock": "index.php"
    }
  ]
}

迁移 app.json ———— 其他配置

小程序 app.json 中 其他字段 -> src/app/app.cml 中配置


<script cml-type="json">
{
  "wx": {
    "window": {
      "backgroundTextStyle":"light",
      "navigationBarBackgroundColor": "#fff",
      "navigationBarTitleText": "Chameleon",
      "navigationBarTextStyle":"black"
    }
  }
}
</script>

迁移 app.js ———— 生命周期映射

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

小程序CML
onLaunchbeforeCreate
onShowmounted
onHidedestroyed

总结

小程序中app.json app.js app.wxss和 src/app/app.cml的对应关系如下

小程序 app.jsCML 项目 src/app/app.cml
app.js<script></script>
app.wxss<style></style>
app.json<script cml-type="json"></script>

迁移页面

新建页面

如上所述,小程序 app.json 中 pages 每个字段,对应router.config.json中每条路由项,对应 CML 项目的每个页面

cml init page

输入 index1

cml init page

输入 index2
...

利用命令行命令,在src/pages中生成对应的页面

迁移页面配置

假设小程序原有页面 index1.json 配置如下

{
  "usingComponents": {
    "my-component1": "/components/comp1",
    "my-component2": "/components/comp2",
    "my-component3": "/components/comp3",
  },
  "navigationBarTitleText": "index",
  "backgroundTextStyle": "dark",
  "backgroundColor": "#E2E2E2"
}

修改src/pages/index1.cml 页面配置,如下:

<script cml-type="json">
{
  "base": {
    "usingComponents": {
     	"my-component1": "/components/comp1",
        "my-component2": "/components/comp2",
        "my-component3": "/components/comp3",
    }
  },
  "wx": {
    "navigationBarTitleText": "index",
    "backgroundTextStyle": "dark",
    "backgroundColor": "#E2E2E2"
  }
}
</script>

其中:

  • base 代表各个小程序页面的共有配置
  • wx 代表微信小程序端特有的配置

迁移页面 ———— 生命周期映射

小程序CML
onLoadcreated
onShowonShow
onReadymounted
onHideonHide
onUnloaddestroyed
onShareAppMessage生命周期多态

总结

1 小程序页面的迁移都要通过 cml init page去初始化这个页面

2 初始化的页面要在src/router.config.json配置对应的path字段

迁移组件

新建组件

如上,index1.json页面中引用了组件 comp1 comp2 comp3;

组件分为:普通组件 和 多态组件

这里以普通组件为例,多态组件具体使用可以参考

cml init component
选择 普通组件(normal-component)
输入 comp1

cml init component
选择 普通组件(normal-component)
输入 comp2

.....

之后,会在 src/components下生成对应的组件;

迁移组件 ———— 配置

同4.2 迁移页面配置

迁移组件 ———— 生命周期映射

小程序CML
createdcreated
attachedbeforeMount
readymounted
detacheddestroyed

总结

1 小程序组件的迁移都要通过 cml init component去初始化这个组件

2 初始化的组件要在使用该组件的地方配置 usingComponents字段

页面&&组件迁移细节

template模板迁移

这里以 CML 语法为例:CML 基础语法

#数据绑定、条件渲染、循环、事件绑定的迁移

假设,原有小程序代码,如下:

<view class="scroller-wrap">
  数据绑定
  <view>{{}}</view>
  条件渲染
  <view wx:if="{{condition1}}">wx:if</view>
  <view wx:elif="{{condition2}}">wx:elif</view>
  <view wx:else>wx:else</view>
  循环
  <view wx:for="{{array}}" wx:for-index="index" wx:for-item="item"></view>
  事件绑定
  <view id="tapTest" data-hi="WeChat" bindtap="tapName">Click me!</view>
</view>

那么,使用 CML 语法后:

<view>
  数据绑定
  <view>{{}}</view>
  条件渲染
  <view c-if="{{condition1}}">c-if</view>
  <view c-else-if="{{condition2}}">c-else-if</view>
  <view c-else>c-else</view>
  循环
  <view c-for="{{array}}" c-for-index="index" c-for-item="item"></view>
  事件绑定
  <view id="tapTest" data-hi="WeChat" bindtap="tapName">Click me!</view>
  CML 语法扩展了事件绑定,支持直接在函数中传参
  <view id="tapTest" bindtap="tapName('weChat',1,2,item)">Click me!</view>
</view>

小程序内置组件 -> cml 内置组件

小程序CML
viewview
texttext
blockblock
scroll-viewscroller
listlist
swipercarousel
buttonbutton
inputinput
textareatextarea
switchswitch
radioradio
checkboxcheckbox
imageimage
videovideo

注意: 小程序和 CML 的内置组件传参是不一样的

小程序原生组件的迁移

对于原生组件,需要在多态组件中调用,并且,需要找到其他端类似的组件。

小程序CML
xxx.web.cml可以再这里调用 Vue 第三方库的组件
xxx.wx.cml可以在这里调用微信第三方组件库或者微信的原生组件(origin-)
xxx.weex.cml可以在这里调用 Weex 第三方组件库


如果希望使用小程序端的原生组件,那么可以在原生标签前加上 origin-,CML 框架会渲染原生组件。

如果想要用微信小程序的第三方组件库

假设,原有小程序代码,如下:

<picker-view value="{{value}}" bindchange="bindChange">
  <picker-view-column>
    <view wx:for="{{list}}"><text>{{item}}</text></view>
  </picker-view-column>
</picker-view>

那么,使用 CML 语法后:

<origin-picker-view value="{{value}}" bindchange="bindChange">
  <origin-picker-view-column>
    <view c-for="{{list}}"><text>{{item}}</text></view>
  </origin-picker-view-column>
</origin-picker-view>

模板上需要替换的语法汇总

小程序CML
wx:ifc-if
wx:elifc-else-if
wx:elsec-else
wx:forc-for
wx:for-indexc-for-index
wx:for-itemc-for-item
wx:keyc-key
bindtapc-bind:tap
catchtapc-catch:tap

CML 对于语法的扩展支持

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

component is 动态组件的扩展

事件绑定支持内联事件传参数

总结

1 对于小程序的语法,比如wx:if wx:for等要替换成 cml 对应的语法 c-if c-for

2 对于小程序的事件绑定,要转化成 CML 的c-bind c-catch的形式,cml 扩展了支持事件传参

JS 内容迁移

数据的迁移

其中需要注意点 小程序中的 properties 对应于 cml 中的 props

小程序

 properties: {
    innerText: {
      type: String,
      value: 'default value',
    }
  },

CML 项目

props = {
  innerText: {
    type: String,
    default: 'default value',
  },
};

微信小程序 API 的迁移

假设,原有小程序代码,如下:

wx.redirectTo({
  url: 'test?id=1',
});

那么,使用 CML 语法后:

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

小程序的 API 文档

这里对于 API 小程序的 API 和 CML 的 API 的文档中对应细则做个简单的表格,如下

微信小程序 APIchameleon-api
wx.canIUsecanIUse
系统信息[系统信息](../api/#getsysteminfo)
计时器计时器
路由路由
交互交互
设置页面 title设置页面 title
动画动画
网络网络
数据缓存数据缓存
获取图片信息获取图片信息
位置位置

以上 chameleon-api提供的接口都是支持跨多端的,对于一些没有提供的跨多端的接口,而你的项目中又是必须用到的情况下,可以通过多态接口来实现。

小程序事件的迁移

注意,自定义组件的事件的触发机制,映射如下:

小程序CML
this.triggerEvent(xxx,xxx)this.$cmlEmit(xxx,xxx)

事件对象参数

CML 对 web native wx 各个端的事件对象进行了统一代理参考

对于灰度区组件(多态组件) 各个端的事件对象还是对应端的事件对象,CML 框架不会对灰度区 origin- 开头的标签和第三方组件标签上绑定的事件进行事件代理

模块化的迁移

小程序的模块化

CML 的模块化

假如 模块文件 m1.js

module.exports = {
  info: 'I am CML',
};

xxx.cml 引用了 m1.js

import cml from 'chameleon-api'; //node_modules中的模块
console.log('cml', cml);
const m1 = require('path/to/m1.js');
console.log('m1', m1.info); // I am CML

总结

1 小程序 JS 层用到的全局变量 wx 要通过 chameleon-api 去替换成对应的,如果没有对应的 API,需要通过多态接口

2 小程序中的properties data对应于 CML 项目 props、data

3 小程序中的除了生命周期之外的事件都对应在 CML 项目中的methods

4 CML 提供了chameleon-store,可以用来存储一些全局的变量

5 小程序触发视图更新的setData不能再使用,chameleon 自带了一套响应式的数据视图绑定

6 模块化中引用的模块要保证多端的适用性,参考chameleon-api

style 内容的迁移

页面布局的迁移

由于 CML 应用是跨多端 Web Native 小程序框架,如果需要跨 native,必须使用 flexbox 进行样式布局,其他场景可以参考只跨 Web 和小程序的应用

关于样式的使用教程

模板上的样式语法,基本和微信小程序是相同的;

样式单位的迁移

如果样式想要适配多端,需要将单位改成cpx;

假设,原有小程序代码,如下:

.demo-com {
  display: flex;
  flex-direction: column;
  align-items: center;
  height: 400rpx;
  justify-content: center;
}
.title {
  align-self: center;
  color: #61c7fc;
  font-size: 72rpx;
  margin-top: 160rpx;
  margin-bottom: 20rpx;
}
.logo {
  width: 150rpx;
  height: 150rpx;
  margin-top: 100rpx;
}

那么,使用 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-top: 160cpx;
  margin-bottom: 20cpx;
}
.logo {
  width: 150cpx;
  height: 150cpx;
  margin-top: 100cpx;
}

以上,简单的介绍了微信小程序迁移到 CML 的简单步骤,如果还有任何疑问,欢迎随时在 CML 官方微信和官方 QQ 群里进行反馈,我们将随时解答你的困惑,再次感谢你对 CML 的支持~

​ Best wishes

​ CML 团队


CML 迁移指南
迁移 Vue 项目到 CML
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }