如何迁移一个Vue项目到chameleon

1 迁移原则:

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

这样可避免以下问题:

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

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

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

2 项目初始化

cml init project

初始化后,cml项目如下:

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

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

假设有下面👇结构的vue项目(vue-cli 2版本生成的)

components下包含各个组件代码,router下是路由配置,store是数据管理中心,config和build下是vue项目的webpack构建的基本配置

接下来就一步步展示如何将这个项目迁移到chameleon

3 工程层面的迁移

3.1 迁移 —— webpack配置

chameleon的工程配置具体参考

chameleon脚手架工具,提供了 dev build两种构建模式,可以对应到 vue 项目中的dev build
vue项目 cml项目
npm run dev cml dev
npm run build cml build
chameleon内置了对于webpack和项目的构建,参考这里修改chameleon内置webpack构建

3.2 迁移 —— store

chameleon中的store使用参考

cml项目中的store和 vue 项目中的store文件下是对应的;

假设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();

3.3 迁移 —— router

1 router-view出口的的对应关系

假设vue项目中入口文件 src/App.vue

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

那么对应着cml项目中的src/app/app.cml,这里的<app>会渲染成<router-view>对应的某个路由;

<template >
  <app store="{{store}}" router-config="{{routerConfig}}"></app>
</template>
2 路由配置对应关系

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 去生成对应的组件

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字段 对应vue中的path字段;

path字段对应着 vue中 import Comp from '/path/to/Comp'中的组件路径

chameleon会自动引入component字段配置的组件,不需要再配置component字段;

总结

1 注意cml项目中不支持路由嵌套,如果有路由嵌套的情况需要考虑转化成组件去实现

2 在迁移路由的时候,要一个一个路由对应着去迁移

3 vue项目中的一级路由的组件都通过 cml init page去初始化这个组件

4 迁移页面/组件

假如 vue 项目中 src/components/HelloWorld.vue组件内有个子组件 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">触发父组件事件</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>

4.1 新建页面/组件

cml init page 

输入 HelloWorld

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

<template>
  <view><text>Hello Chameleon!</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中生成对应的组件

<template>
  <view><text>Hello Chameleon!</text></view>
</template>

<script>

class Comp {

  //...
}

export default new Comp();
</script>
<style>

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

4.2 迁移组件引用

假设vue项目src/components/HelloWorld.vue中引用了其他组件 import comp from './comp.vue';

对应到cml项目 组件需要在 usingComponents 引用,不需要在配置 components字段

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

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

总结

1 router.js中对应的组件需要通过 cml init page生成,然后在 router.config.js中配置对应路由

2 组件内部引用的子组件要通过cml init component 生成 ,然后通过usingComponents字段去引用

3 组件内引用的其他js库,比如import lodash from 'lodash'仍然通过import的形式引用

5 页面&&组件迁移细节

5.1 template模板迁移

这里以cml的vue 语法为例:cml类vue基础语法

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

假设,原有vue项目代码,如下:

<div class="scroller-wrap">
    数据绑定
    <div>{{}}</div>
    条件渲染
    <div v-if="condition">v-if</div>
    <div v-else-if="condition1">v-else-if</div>
    <div v-else>v-else</div>
    循环
    <div v-for="(item ,index) in array"></div>
    事件绑定
    <div id="tapTest" @click="handleClick">Click me!</div>
</div>

那么,使用 cml的类vue语法后:整体基本上不用变,只需要将标签改成cml的内置标签即可参考

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

<template  lang="vue">
<view class="scroller-wrap">
    数据绑定
    <view>{{}}</view>
    条件渲染
    <view v-if="condition">v-if</view>
    <view v-else-if="condition1">v-else-if</view>
    <view v-else>v-else</view>
    循环
    <view v-for="(item ,index) in array"></view>
    事件绑定
    <view id="tapTest" @click="handleClick">Click me!</view>
</view></template>

5.1.2 vue项目标签 -> cml标签

vue项目 cml
div view
text span text
img image
input input 组件
button button 组件
textarea textarea 组件
switch switch 组件
radio radio 组件
checkbox checkbox 组件
image image 组件
video video 组件
没有列出来的标签比如head p main等等只能在多态组件中使用,不支持跨多端
对于 a标签的 href,如果想要达到跨多端的效果,需要通过绑定事件使用 chameleon-api去跳转。

5.1.3 chameleon对于语法的扩展支持

指令的扩展 c-show、c-model、c-show 参考
component is 动态组件的扩展 参考
事件绑定支持内联事件传参数 参考

5.1.4 迁移注意点

  • cml支持的类vue语法 ,只有在文档中列出的语法才支持多端,其他没有列出的语法仅可以在web端使用,跨端没有支持,比如 v-htm class的对象语法 数组语法等

根据以上教程,我们可以迁移HelloWorld.vuecomp.vue中的模板内容了

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>触发父组件事件</text></view>
  </view>
</template>

5.2 JS内容迁移

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

5.2.2 数据的迁移 参考

5.2.3 vue项目API的迁移

API迁移包括 http请求 路由跳转 本地存储等 参考:chameleon-api的文档

假设,原有vue项目代码,如下:

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

跨多端的路由仅支持 传入path字段进行路由,不支持路由 name字段的路由

那么,使用cml语法后:

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

5.2.4 事件的触发机制,映射如下:

vue项目 cml
this.$emit(xxx,xxx) this.$cmlEmit(xxx,xxx)
事件对象参数
  • chameleon对web native wx各个端的事件对象进行了统一代理 参考
  • 对于灰度区组件(多态组件) 各个端的事件对象还是对应端的事件对象,chameleon框架不会对灰度区origin-开头的标签和第三方组件 标签上绑定的事件进行事件代理
事件冒泡
chameleon生成的weex项目默认都是开启了支持事件冒泡的机制
同时扩展了阻止事件冒泡的语法;

vue语法(仅仅支持 .stop)

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

cml语法

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

总结

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

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

根据以上教程,我们可以迁移HelloWorld.vuecomp.vue中的js内容了

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>

5.3 style内容的迁移

5.3.1 页面布局的迁移

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

关于样式的使用教程 参考

模板上的样式语法 参考

5.3.2 样式单位的迁移

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

👉 根据以上教程,我们可以迁移HelloWorld.vuecomp.vue中的js内容了

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;
}

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

​ Best wishes

​ Chameleon 团队

results matching ""

    No results matching ""