我们用5分钟写了一个跨多端项目

cml 作为真正让一套代码运行多端的框架,提供标准的MVVM模式,统一开发各类终端。同时,拥有各端独立的运行时框架(runtime)、数据管理(store)、组件库(ui)、接口(api)。此外,cml在跨端能力加强、能力统一、表现一致等方面做了许多工作。

\n

今天,为了让大家的项目优雅升级,快速接入,给你带来一份丰盛的cml迁移指南~

\n

\n

源码地址:https://github.com/jalonjs/cml-first-demo

\n

目录结构

\n

和微信小程序一样,cml 包含一个描述整体程序的 app 和多个描述各自页面的 page

\n

小程序目录结构

\n
.\n├── components // 包含各个组件\n├── pages // 包含各个页面\n├── app.js // 包含各个组件\n├── app.js  // 应用启动入口\n├── app.json // 全局配置\n├── app.wxss // 全局样式\n└── project.config.json // 项目配置文件\n\n
\n

cml目录结构

\n
.\n├── dist // 各个端构建结果\n│   ├── alipay \n│   ├── baidu \n│   ├── wx \n│   ├── web  \n│   ├── weex \n│   └── config.json // 跨端配置map映射表\n├── node_modules // 第三方库\n├── mock // 模拟 接口数据 和 模板数据\n├── src  // 源代码开发目录\n│   ├── app // 应用启动入口\n│   ├── assets // 静态资源\n│   ├── components // 包含组件\n│   ├── pages  // 包含页面\n│   ├── store //数据管理\n│   └── router.config.json // 路由配置文件\n├── chameleon.config.js // 项目配置文件\n└── package.json // npm包配置文件\n\n
\n

如何修改配置

\n

在小程序项目里面,分为:

\n

小程序 —— 项目配置

\n

可以在项目根目录使用 project.config.json 文件对项目进行配置。

\n

配置示例:

\n
{\n  \u0026quot;miniprogramRoot\u0026quot;: \u0026quot;./src\u0026quot;,\n  \u0026quot;debugOptions\u0026quot;: {}\n}\n
\n

小程序 —— 全局配置

\n

小程序根目录下的 app.json 文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等

\n

配置示例:

\n
{\n  \u0026quot;pages\u0026quot;: [\u0026quot;pages/index/index\u0026quot;, \u0026quot;pages/logs/index\u0026quot;],\n  \u0026quot;window\u0026quot;: {\n    \u0026quot;navigationBarTitleText\u0026quot;: \u0026quot;Demo\u0026quot;\n  },\n  \u0026quot;networkTimeout\u0026quot;: {\n    \u0026quot;request\u0026quot;: 10000,\n    \u0026quot;downloadFile\u0026quot;: 10000\n  }\n}\n
\n

小程序 —— 页面配置

\n

每一个小程序页面也可以使用 .json 文件来对本页面的窗口表现进行配置。

\n

页面的配置只能设置 app.json 中部分 window 配置项的内容,页面中配置项会覆盖 app.jsonwindow 中相同的配置项。

\n

配置示例:

\n
{\n  \u0026quot;navigationBarBackgroundColor\u0026quot;: \u0026quot;#ffffff\u0026quot;,\n  \u0026quot;navigationBarTextStyle\u0026quot;: \u0026quot;black\u0026quot;,\n  \u0026quot;navigationBarTitleText\u0026quot;: \u0026quot;微信接口功能演示\u0026quot;,\n  \u0026quot;backgroundColor\u0026quot;: \u0026quot;#eeeeee\u0026quot;,\n  \u0026quot;backgroundTextStyle\u0026quot;: \u0026quot;light\u0026quot;\n}\n
\n

同样,在 cml项目里面,分为以下几种配置方案。

\n

cml —— 项目配置

\n

chameleon.config.js 为项目的配置文件,你可以定制化构建,比如是否带hash,是否\u0008压缩等等。

\n

配置示例:

\n
// 设置静态资源的线上路径\nconst publicPath = '//www.static.chameleon.com/static';\n// 设置api请求前缀\nconst apiPrefix = 'https://api.chameleon.com';\n// 合并配置\ncml.config.merge({\n  wx: {\n    build: {apiPrefix}\n  },\n  alipay: {\n    build: {apiPrefix}\n  },\n  baidu: {\n    build: {apiPrefix}\n  },\n  web: {\n    dev: {\n      hot: true,\n      console: true\n    },\n    build: {\n      publicPath: `${publicPath}/web`,\n      apiPrefix\n    }\n  },\n  weex: {\n    build: {\n      publicPath: `${publicPath}/weex`,\n      apiPrefix\n    }\n  }\n})\n\n
\n

cml —— 全局配置

\n

cml 项目 app 目录下的 app.cml 文件的 \u0026lt;script cml-type=\u0026quot;json\u0026quot; /\u0026gt; 用来对 cml应用 进行全局配置,具有 跨端配置 和 差异化 的能力

\n

配置示例:

\n
\u0026lt;script cml-type=\u0026quot;json\u0026quot;\u0026gt;\n{\n  \u0026quot;base\u0026quot;: {\n    \u0026quot;window\u0026quot;: {\n      \u0026quot;navigationBarTitleText\u0026quot;: \u0026quot;各个端共同title\u0026quot;,\n    },\n    \u0026quot;permission\u0026quot;: {\n      \u0026quot;scope.userLocation\u0026quot;: {\n        \u0026quot;desc\u0026quot;: \u0026quot;你的位置信息将用于小程序位置接口的效果展示\u0026quot;\n      }\n    }\n  },\n  \u0026quot;wx\u0026quot;: {\n    \u0026quot;window\u0026quot;: {\n      \u0026quot;backgroundTextStyle\u0026quot;:\u0026quot;light\u0026quot;,\n      \u0026quot;navigationBarBackgroundColor\u0026quot;: \u0026quot;#fff\u0026quot;,\n      \u0026quot;navigationBarTitleText\u0026quot;: \u0026quot;差异化 title\u0026quot;,\n      \u0026quot;navigationBarTextStyle\u0026quot;:\u0026quot;black\u0026quot;\n    }\n  },\n  \u0026quot;baidu\u0026quot;: {\n    \u0026quot;window\u0026quot;: {\n      \u0026quot;backgroundTextStyle\u0026quot;: \u0026quot;light\u0026quot;\n    }\n  },\n  \u0026quot;alipay\u0026quot;: {\n      \u0026quot;window\u0026quot;: {\n        \u0026quot;defaultTitle\u0026quot;: \u0026quot;Chameleon\u0026quot;\n      }\n  }\n}\n\u0026lt;/script\u0026gt;\n
\n

cml —— 页面/组件配置

\n

通过 usingComponents 配置 组件路径 注册引用的组件。

\n

配置示例:

\n
\u0026lt;script cml-type=\u0026quot;json\u0026quot;\u0026gt;\n{\n  \u0026quot;base\u0026quot;: {\n    \u0026quot;usingComponents\u0026quot;: {\n      \u0026quot;navi\u0026quot;: \u0026quot;/components/navi/navi\u0026quot;,\n      \u0026quot;navi-npm\u0026quot;: \u0026quot;cml-test-ui/navi/navi\u0026quot;\n    }\n  },\n  \u0026quot;wx\u0026quot;: {\n  },\n  \u0026quot;alipay\u0026quot;: {\n  },\n  \u0026quot;baidu\u0026quot;: {\n  },\n  \u0026quot;web\u0026quot;: {\n  },\n  \u0026quot;weex\u0026quot;: {\n  }\n}\n\u0026lt;/script\u0026gt;\n
\n

如何使用路由能力?

\n

小程序配置路由

\n

app.json配置项列表的 pages 字段用于指定小程序由哪些页面组成,每一项都对应一个页面的 路径+文件名 信息。

\n

数组的第一项代表小程序的初始页面(首页)。新增/减少页面,需要对 pages 数组进行修改。

\n

如果项目有 pages/index/index.wxmlpages/logs/logs.wxml 两个页面,则需要在 app.json 中写

\n
{\n  \u0026quot;pages\u0026quot;: [\u0026quot;pages/index/index\u0026quot;, \u0026quot;pages/logs/logs\u0026quot;]\n}\n
\n

cml配置路由

\n

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

\n
{\n  \u0026quot;mode\u0026quot;: \u0026quot;history\u0026quot;,\n  \u0026quot;domain\u0026quot;: \u0026quot;https://www.chameleon.com\u0026quot;,\n  \u0026quot;routes\u0026quot;:[\n    {\n      \u0026quot;url\u0026quot;: \u0026quot;/cml/h5/index\u0026quot;,\n      \u0026quot;path\u0026quot;: \u0026quot;/pages/index/index\u0026quot;,\n      \u0026quot;mock\u0026quot;: \u0026quot;index.php\u0026quot;\n    },\n    {\n      \u0026quot;url\u0026quot;: \u0026quot;/cml/h5/logs\u0026quot;,\n      \u0026quot;path\u0026quot;: \u0026quot;pages/logs/logs\u0026quot;,\n      \u0026quot;mock\u0026quot;: \u0026quot;logs.php\u0026quot;\n    }\n  ]\n}\n
\n

文件名不需要写文件后缀,cml框架会自动去寻找对于位置的 .cml 文件进行处理。

\n

小程序使用路由

\n \n

cml使用路由

\n

依据统一资源索引URI,自适应打开不同环境同一路由PATH:

\n
  • \n
  • \n

    打开新页面:调用 chameleon-api cml.navigateTo

    \n\n
  • \n

    页面重定向:调用 chameleon-api cml.redirectTo

    \n\n
  • \n

    页面返回:调用 chameleon-api cml.navigateBack

    \n\n
  • \n

    打开另一个跨端应用:调用 chameleon-api cml.open

    \n\n
  • \n

    返回到上一个跨端应用:调用 chameleon-api cml.close

    \n\n
\n

如何注册

\n

小程序注册

\n

在小程序项目里面,App() 函数用来注册一个小程序。接受一个 Object 参数,其指定小程序的生命周期回调等。

\n

示例代码

\n
App({\n  onLaunch(options) {\n    // Do something initial when launch.\n  },\n  globalData: 'I am global data'\n})\n
\n

cml注册程序

\n

示例代码

\n
\u0026lt;script\u0026gt;\nimport store from '../store/index.js'\nimport routerConfig from '../router.config.json';\n\nclass App {\n  data = {\n    store,\n    routerConfig\n  }\n  created(res) {\n  }\n}\n\nexport default new App();\n\u0026lt;/script\u0026gt;\n
\n

细心的你会发现,

\n

小程序中app.json app.js app.wxsssrc/app/app.cml的对应关系如下:

\n

\"\"

\n

小程序注册页面

\n

在小程序项目里面,Page(Object) 函数用来注册一个页面。接受一个 Object 类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。

\n

示例代码:

\n
// index.js\nPage({\n  data: {\n    text: 'This is page data.'\n  },\n  changeText: function(e) {\n    // sent data change to view\n    this.setData({\n      text: 'CML'\n    })\n  }\n})\n
\n

cml注册页面

\n

示例代码

\n
\u0026lt;script\u0026gt;\nclass Index {\n  data = {\n    text: 'Chameleon'\n  }\n  methods = {\n    changeText: function(e) {\n      // sent data change to view\n      this.text = 'CML';\n    }\n  }\n  computed = {}\n  watch = {}\n};\nexport default new Index();\n\u0026lt;/script\u0026gt;\n
\n

小程序注册组件

\n

在小程序项目里面,
\nComponent(Object) 构造器可用于定义组件,调用 Component 构造器时可以指定组件的属性、数据、方法等。

\n

示例代码

\n
Component({\n  properties: {\n    myProperty: { // 属性名\n      type: String, // 类型(必填)\n      value: '' // 属性初始值(可选)\n    },\n    myProperty2: String // 简化的定义方式\n  },\n  data: {\n    text: ''\n  }, // 私有数据,可用于模板渲染\n\n  // 生命周期函数,可以为函数,或一个在methods段中定义的方法名\n  attached() { }, \n  ready() { },\n  methods: {\n    onMyButtonTap() {\n      this.setData({\n        // 更新属性和数据的方法与更新页面数据的方法类似\n        text: 'wx'\n      })\n    }\n  }\n})\n
\n

cml注册组件

\n

示例代码

\n
\u0026lt;script\u0026gt;\nclass MyComponent {\n  props = {\n    myProperty: { // 属性名\n      type: String, // 类型(必填)\n      default: '' // 属性初始值(可选)\n    },\n    myProperty2: String // 简化的定义方式\n  }\n  data =  {\n    text: ''\n  } // 私有数据,可用于模板渲染\n\n  beforeMount() {}\n  mounted() {}\n  methods = {\n    onMyButtonTap() {\n      this.text = 'cml'\n    }\n  }\n  computed = {}\n  watch = {}\n};\nexport default new MyComponent();\n\u0026lt;/script\u0026gt;\n
\n

如何声明生命周期

\n

统一各端应用生命周期的定义,是跨端框架的重要组成,也是迁移的必经之路。

\n

小程序声明生命周期

\n

可以在 App(Object)Page(Object)Component(Object) 传入Object参数,其指定小程序的生命周期回调等。

\n

代码示例

\n
// index.js\nPage({\n  onLoad(options) {\n    // Do some initialize when page load.\n  },\n  onReady() {\n    // Do something when page ready.\n  },\n  onShow() {\n    // Do something when page show.\n  },\n  onHide() {\n    // Do something when page hide.\n  },\n  onUnload() {\n    // Do something when page close.\n  },\n  onShareAppMessage() {\n    // return custom share data when user share.\n  }\n})\n
\n

cml声明生命周期

\n

.cml 文件 \u0026lt;script /\u0026gt; 代码块返回的对象实例,其指定生命周期回调

\n

示例代码

\n
\u0026lt;script\u0026gt;\nclass Index {\n  beforeCreate(query) {\n    // data数据挂载到this根节点上之前,以及methods所有方法挂载到实例根节点之前\n    // 注意:只用页面的 beforeCreate钩子 会返回页面query\n    console.log('App beforeCreate: 打开当前页面路径中的参数是 ', query)\n  }\n  created() {\n    // data,methods里面的这些events挂载完成\n    console.log('App created')\n  }\n  beforeMount() {\n    // 开始挂载已经编译完成的cml到对应的节点时\n    console.log('App beforeMount')\n  }\n  mounted() {\n    // cml模板编译完成,且渲染到dom中完成,在整个生命周期中只执行一次\n    console.log('App mounted')\n  }\n  beforeDestroy() {\n    // 实例销毁前\n    console.log('App beforeDestroy')\n  }\n  destroyed() {\n    // 实例销毁后\n    console.log('App destroyed')\n  }\n};\nexport default new Index();\n\u0026lt;/script\u0026gt;\n
\n

App 生命周期映射

\n

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

\n

\"\"

\n

Page 生命周期映射

\n

小程序 Page()中的生命周期 -\u0026gt; cml src/pages/mypage/mypage.cml

\n

\"\"

\n

Component 生命周期映射

\n

小程序 Component()中的生命周期 -\u0026gt; cml src/components/mycomponent/mycomponent.cml

\n

\"\"

\n

生命周期总结

\n

每个 cml 实例(AppPageComponent)在被创建时都要经过一系列的初始化过程。

\n

例如,需要设置数据监听、编译模板、将实例挂载到 \u0008CML节点 并在数据变化时更新 \u0008CML节点 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给开发者在不同阶段添加自己的代码的机会。

\n

cmlApp页面Page组件Component 提供了一系列生命周期事件,保障应用有序执行。

\n

另外,如果你想使用某个端特定的生命周期,你可以从业务出发使用生命周期多态

\n

数据如何响应到视图

\n

如今,双向数据绑定\u0026amp;单向数据流 已深入开发者日常,MVMM开发模式算是框架标配。

\n

数据绑定条件渲染列表渲染 是如何书写的呢?

\n

示例代码

\n

小程序使用数据响应

\n
\u0026lt;!--wxml--\u0026gt;\n\u0026lt;view class=\u0026quot;scroller-wrap\u0026quot;\u0026gt;\n    \u0026lt;!--数据绑定--\u0026gt;\n  \u0026lt;view\u0026gt;{{message}}\u0026lt;/view\u0026gt;\n  \u0026lt;!--条件渲染--\u0026gt;\n  \u0026lt;view wx:if=\u0026quot;{{view == 'WEBVIEW'}}\u0026quot;\u0026gt;WEBVIEW\u0026lt;/view\u0026gt;\n  \u0026lt;view wx:elif=\u0026quot;{{view == 'APP'}}\u0026quot;\u0026gt;APP\u0026lt;/view\u0026gt;\n  \u0026lt;view wx:else=\u0026quot;{{view == 'MINA'}}\u0026quot;\u0026gt;MINA\u0026lt;/view\u0026gt;\n    \u0026lt;!--列表渲染--\u0026gt;\n  \u0026lt;view wx:for=\u0026quot;{{array}}\u0026quot; wx:for-index=\u0026quot;index\u0026quot; wx:for-item=\u0026quot;item\u0026quot;\u0026gt;{{item}}\u0026lt;/view\u0026gt;\n\u0026lt;/view\u0026gt;\n
\n
// page.js\nPage({\n  data: {\n    message: 'Hello MINA!',\n    view: 'MINA',\n    array: [1, 2, 3, 4, 5]\n  },\n  onLoad() {\n    this.setData({\n      message: 'wx'\n    })\n  }\n})\n
\n

cml使用数据响应

\n
\u0026lt;template\u0026gt;\n\u0026lt;!--index.cml--\u0026gt;\n\u0026lt;view class=\u0026quot;scroller-wrap\u0026quot;\u0026gt;\n    \u0026lt;!--数据绑定--\u0026gt;\n  \u0026lt;view\u0026gt;{{message}}\u0026lt;/view\u0026gt;\n  \u0026lt;!--条件渲染--\u0026gt;\n  \u0026lt;view c-if=\u0026quot;{{view == 'WEBVIEW'}}\u0026quot;\u0026gt;WEBVIEW\u0026lt;/view\u0026gt;\n  \u0026lt;view c-else-if=\u0026quot;{{view == 'APP'}}\u0026quot;\u0026gt;APP\u0026lt;/view\u0026gt;\n  \u0026lt;view c-else=\u0026quot;{{view == 'MINA'}}\u0026quot;\u0026gt;MINA\u0026lt;/view\u0026gt;\n    \u0026lt;!--列表渲染--\u0026gt;\n  \u0026lt;view c-for=\u0026quot;{{array}}\u0026quot; c-for-index=\u0026quot;index\u0026quot; c-for-item=\u0026quot;item\u0026quot;\u0026gt;{{item}}\u0026lt;/view\u0026gt;\n\u0026lt;/view\u0026gt;\n\u0026lt;/template\u0026gt;\n\u0026lt;script\u0026gt;\nclass Index {\n  data =  {\n    message: 'Hello MINA!',\n    view: 'MINA',\n    array: [1, 2, 3, 4, 5]\n  }\n\n  beforeCreate () {\n    this.message = 'cml'\n  }\n};\nexport default new Index();\n\u0026lt;/script\u0026gt;\n
\n

数据响应总结

\n

cml运行时框架 提供了跨端响应式数据绑定系统(Data binding),当做数据修改的时候,只需要在逻辑层修改数据,视图层就会做相应的更新。

\n

只需要将 view\u0026lt;--\u0026gt;model 交互部分逻辑,作简单迁移,便可使它成为跨多端的数据响应系统。

\n

事件交互

\n

cml 支持一些基础的事件,保障各端效果(类型绑定事件对象)一致运行。

\n

示例代码

\n

小程序使用事件

\n
\u0026lt;!--wxml--\u0026gt;\n\u0026lt;view id=\u0026quot;tapTest\u0026quot; data-hi=\u0026quot;WeChat\u0026quot; bindtap=\u0026quot;tapName\u0026quot;\u0026gt;Click me!\u0026lt;/view\u0026gt;\n
\n
// page.js\nPage({\n  tapName(event) {\n    console.log(event)\n  }\n})\n
\n

cml使用事件

\n
\u0026lt;template\u0026gt;\n  \u0026lt;view id=\u0026quot;tapTest\u0026quot; data-hi=\u0026quot;WeChat\u0026quot; c-bind:tap=\u0026quot;tapName\u0026quot;\u0026gt;\n    \u0026lt;text\u0026gt;Click me!\u0026lt;/text\u0026gt;\n  \u0026lt;/view\u0026gt;\n\u0026lt;/template\u0026gt;\n\u0026lt;script\u0026gt;\nclass Index {\n  methods = {\n    tapName(e) {\n      // 打印事件对象\n      console.log('事件对象:', e);\n    }\n  }\n}\nexport default new Index();\n\u0026lt;/script\u0026gt;\n
\n

事件使用总结

\n

同时,还支持自定义事件,用于父子组件之间的通信。

\n

另外,如果你想要使用某个端特定的事件,cml 并不会限制你的自由发挥,你可以从业务出发使用 组件多态 或者 接口多态 差异化实现功能。

\n

布局和外观

\n

各端描述 布局和外观层叠样式表(CSS)实现存在差异,包括不限于 布局盒模型定位文本

\n

所以, cml 框架内置跨端一致性基础样式能力。

\n

并且,定义了用于描述页面的样式规范CMSS(Chameleon Style Sheet)。

\n

如何导入外部样式

\n

使用 @import 语句可以导入外联样式表,@import 后跟需要导入的外联样式表的相对路径,用 ; 表示语句结束。

\n

小程序导入外部样式

\n

示例代码:

\n
/** common.wxss **/\n.small-p {\n  padding:5px;\n}\n
\n
/** app.wxss **/\n@import \u0026quot;common.wxss\u0026quot;;\n.middle-p {\n  padding:15px;\n}\n
\n

cml导入外部样式

\n

详细文档:https://cmljs.org/doc/api/runtime/@import.html

\n

示例代码:

\n
/** common.css **/\n.small-p {\n  padding: 5px;\n}\n
\n
\u0026lt;!-- app.cml --\u0026gt;\n\u0026lt;style\u0026gt;\n  @import './common.css';\n  .middle-p {\n    padding:15 cpx;\n  }\n\u0026lt;/style\u0026gt;\n
\n

样式使用总结

\n

同时,为了统一多端尺寸单位,呈现效果一致,同时页面响应式布局,cml 项目统一采用 cpx 作为尺寸单位,规定以屏幕750px(占满屏幕)视觉稿作为标准。

\n

而且,各端样式表拥有的能力不尽相同,是项目迁移的主要阵地之一。

\n

另外,如果你想要使用某个端特定的样式能力,cml 并不会限制你的自由发挥,你可以从业务出发使用样式多态

\n

注意:由于chameleon应用是 跨多端web native 小程序框架,如果需要跨native,必须使用 flexbox 进行样式布局!!!

\n

组件

\n

cml 项目一切皆组件。组件(Component)是视图的基本组成单元。

\n

框架为开发者提供了一系列基础组件,开发者可以通过组合这些基础组件进行快速开发。

\n

如:

\n
\u0026lt;template\u0026gt;\n  \u0026lt;view\u0026gt;\n    \u0026lt;view\u0026gt;view 基础组件\u0026lt;/view\u0026gt;\n    \u0026lt;text\u0026gt;text 基础组件\u0026lt;/text\u0026gt;\n  \u0026lt;/view\u0026gt;\n\u0026lt;/template\u0026gt;\n
\n

同时,cml 支持简洁的组件化编程。

\n

自定义组件

\n

开发者可以将页面内的功能模块抽象成自定义组件,以便在不同的页面中重复使用。自定义组件在使用时与基础组件非常相似。

\n

如何创建自定义组件

\n

小程序创建自定义组件

\n

代码示例:

\n
Component({\n  properties: {\n    // 这里定义了innerText属性,属性值可以在组件使用时指定\n    innerText: {\n      type: String,\n      value: 'default value',\n    }\n  },\n  data: {\n    // 这里是一些组件内部数据\n    someData: {}\n  },\n  methods: {\n    // 这里是一个自定义方法\n    customMethod() {}\n  }\n})\n
\n

cml创建自定义组件

\n

示例代码

\n
\u0026lt;script\u0026gt;\nclass MyComponent {\n  props = {\n    // 这里定义了innerText属性,属性值可以在组件使用时指定\n    innerText: {\n      type: String,\n      value: 'default value',\n    }\n  }\n  data = {\n    // 这里是一些组件内部数据\n    someData: {}\n  }\n  methods = {\n    // 这里是一个自定义方法\n    customMethod() {}\n  }\n  computed = {}\n  watch = {}\n};\nexport default new MyComponent();\n\u0026lt;/script\u0026gt;\n
\n

如何使用自定义组件

\n

使用已注册的自定义组件前,首先要进行引用声明。此时需要提供每个自定义组件的标签名和对应的自定义组件文件路径。

\n

代码示例:

\n

page.json 中进行引用声明

\n
{\n  \u0026quot;usingComponents\u0026quot;: {\n    \u0026quot;component-tag-name\u0026quot;: \u0026quot;path/to/the/custom/component\u0026quot;\n  }\n}\n
\n

page.wxml 中使用

\n
\u0026lt;view\u0026gt;\n  \u0026lt;!-- 以下是对一个自定义组件的引用 --\u0026gt;\n  \u0026lt;component-tag-name inner-text=\u0026quot;Some text\u0026quot;\u0026gt;\u0026lt;/component-tag-name\u0026gt;\n\u0026lt;/view\u0026gt;\n
\n

cml使用自定义组件

\n

代码示例:

\n

page.cml\u0026lt;script cml-type='json' /\u0026gt;进行引用声明

\n
\u0026lt;script cml-type=\u0026quot;json\u0026quot;\u0026gt;\n{\n  \u0026quot;base\u0026quot;: {\n      \u0026quot;usingComponents\u0026quot;: {\n        \u0026quot;component-tag-name\u0026quot;: \u0026quot;path/to/the/custom/component\u0026quot;\n      }\n  }\n}\n\u0026lt;/script\u0026gt;\n
\n

page.cml\u0026lt;template /\u0026gt;使用

\n
\u0026lt;template\u0026gt;\n\u0026lt;view\u0026gt;\n  \u0026lt;!-- 以下是对一个自定义组件的引用 --\u0026gt;\n  \u0026lt;component-tag-name inner-text=\u0026quot;Some text\u0026quot;\u0026gt;\u0026lt;/component-tag-name\u0026gt;\n\u0026lt;/view\u0026gt;\n\u0026lt;/template\u0026gt;\n
\n

如何实现父子组件事件通信

\n

事件系统是组件间通信的主要方式之一。自定义组件可以触发任意的事件,引用组件的页面可以监听这些事件。

\n

小程序组件通信

\n

代码示例:

\n
\u0026lt;!-- 页面 page.wxml --\u0026gt;\n\u0026lt;view\u0026gt;\n  \u0026lt;my-component bindcustomevent=\u0026quot;onMyEvent\u0026quot;\u0026gt;\u0026lt;/my-component\u0026gt;\n\u0026lt;/view\u0026gt;\n
\n
// 页面 page.js\nPage({\n  methods: {\n    onMyEvent(e) {\n      console.log(e.detail) // 自定义组件触发事件时提供的detail对象\n    }\n  }\n})\n
\n
\u0026lt;!-- 组件 my-component.wxml --\u0026gt;\n\u0026lt;view\u0026gt;\n  \u0026lt;button bindtap=\u0026quot;onTap\u0026quot;\u0026gt;点击这个按钮将触发“myevent”事件\u0026lt;/button\u0026gt;\n\u0026lt;/view\u0026gt;\n
\n
// 组件 my-component.js\nComponent({\n  methods: {\n    onTap() {\n      this.triggerEvent('customevent', {}) // 触发 自定义组件事件\n    }\n  }\n})\n
\n

cml组件通信

\n

代码示例:

\n
\u0026lt;!-- 页面 page.cml --\u0026gt;\n\u0026lt;template\u0026gt;\n  \u0026lt;view\u0026gt;\n    \u0026lt;my-component c-bind:customevent=\u0026quot;onMyEvent\u0026quot;\u0026gt;\u0026lt;/my-component\u0026gt;\n  \u0026lt;/view\u0026gt;\n\u0026lt;/template\u0026gt;\n\u0026lt;script\u0026gt;\nclass Index {\n  methods = {\n    // 这里是一个自定义方法\n    onMyEvent(e) {\n      console.log(e.detail) // 自定义组件触发事件时提供的detail对象\n    }\n  }\n};\nexport default new Index();\n\u0026lt;/script\u0026gt;\n\u0026lt;script cml-type=\u0026quot;json\u0026quot;\u0026gt;\n{\n  \u0026quot;base\u0026quot;: {\n      \u0026quot;usingComponents\u0026quot;: {\n        \u0026quot;my-component\u0026quot;: \u0026quot;path/to/the/custom/component\u0026quot;\n      }\n  }\n}\n\u0026lt;/script\u0026gt;\n
\n
\u0026lt;!-- 页面 path/to/the/custom/component.cml --\u0026gt;\n\u0026lt;template\u0026gt;\n  \u0026lt;view\u0026gt;\n    \u0026lt;button c-bind:tap=\u0026quot;onTap\u0026quot;\u0026gt;点击这个按钮将触发“myevent”事件\u0026lt;/button\u0026gt;\n  \u0026lt;/view\u0026gt;\n\u0026lt;/template\u0026gt;\n\u0026lt;script\u0026gt;\nclass MyComponent {\n  methods = {\n    // 这里是一个自定义方法\n    onTap() {\n      this.$cmlEmit('customevent', {}) // 触发 自定义组件事件\n    }\n  }\n};\nexport default new MyComponent();\n\u0026lt;/script\u0026gt;\n\u0026lt;script cml-type=\u0026quot;json\u0026quot;\u0026gt;\n{}\n\u0026lt;/script\u0026gt;\n
\n

组件使用总结

\n

和小程序一样,cml框架 提供了大量内置组件扩展组件,抹平多端差异,便于开发者通过组合这些组件,创建出强大的应用程序。

\n

扩展组件需要额外引入。如:

\n
\u0026lt;script cml-type=\u0026quot;json\u0026quot;\u0026gt;\n{\n  \u0026quot;base\u0026quot;: {\n      \u0026quot;usingComponents\u0026quot;: {\n        \u0026quot;c-dialog\u0026quot;: \u0026quot;cml-ui/components/c-dialog/c-dialog\u0026quot;\n      }\n  }\n}\n\u0026lt;/script\u0026gt;\n
\n

在执行 cml build 构建打包时,cml 框架 会按需打包引用的内置组件和扩展组件,为代码瘦身。

\n

内置组件扩展组件都是支持跨多端的,对于一些没有提供的某个端的组件,可以通过组件多态来实现。

\n

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

\n

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

\n

如在 map.wx.cml 文件中使用原生地图组件 \u0026lt;map/\u0026gt;

\n
\u0026lt;!-- map.wx.cml --\u0026gt;\n\u0026lt;template\u0026gt;\n  \u0026lt;origin-map\n    id=\u0026quot;map\u0026quot;\n    longitude=\u0026quot;113.324520\u0026quot;\n    latitude=\u0026quot;23.099994\u0026quot;\n    controls=\u0026quot;{{controls}}\u0026quot;\n    bindcontroltap=\u0026quot;controltap\u0026quot;\n    style=\u0026quot;width: 100%; height: 300px;\u0026quot;\n  \u0026gt;\u0026lt;/origin-map\u0026gt;\n\u0026lt;/template\u0026gt;\n
\n

如何调用平台接口能力

\n

在小程序里面,可以通过微信原生 API,调起如获取用户信息,本地存储,支付功能等。

\n

示例代码

\n
try {\n  wx.setStorageSync('name', 'Hanks')\n} catch (e) {\n  console.error(e)\n}\n
\n

同样,在 cml 项目里面可以这样调用:

\n

示例代码

\n
import cml from 'chameleon-api'\ncml.setStorage('name', 'Hanks').then((res)=\u0026gt;{\n  console.log(res)\n},function(e){\n  console.error(e)\n})\n
\n

接口使用总结

\n

cml 框架提供了丰富的多态接口,可以调起各端提供的原生能力,如系统信息、元素节点信息、动画效果、本地存储、网络请求、地理位置等。请参考 API 文档。

\n

chameleon-api提供的接口都是支持跨多端的,对于一些没有提供的某个端的原生接口,可以通过接口多态来调用。

\n

迁移实例

\n

下面给出各端(vue、weex、小程序)迁移cml指南 以及 cml 导出组件到各端指南的具体迁移文档:

\n \n

更多内容,请关注前端之巅。

\n

\"\"

\n
hao123网址站ASP开源源码正式发布 本程序源码由hao123.com网址站独立开发,更新hao123最新样式和分类,asp版带后台,可全站生成静态页。 关于网站LOGO修改: 首页网站标志LOGO目录位置:/images/logo_140.gif 次页网站标志LOGO目录位置:/logo.gif 希望大家创建有自己特色的LOGO,以区别于hao123。 默认后台地址:/admin/login.asp 默认用户:admin 默认密码: admin 关于网站安装: 1, 上传源码,进入后台->全局->站点信息,把信息修改成你站信息 2, 生成首页和所有分类HTML 建议上传后修改默认管理后台地址/admin/的名称。 演式地址:http://www.86daijia.net 2012-5-16 增加站长统计程序及图标。 2012-5-16 美化界面。 2012-5-16 增加最新新闻资讯。 2012-5-16 修正后台管理全局设置不能保存BUG。 2012-4-9 增加IP购买页面。 2012-4-9 增加分享工具条。 2012-4-9 增加下角话费充值条 2012-4-9 支持二级目录,为站长节省空间 2012-2-27 再次与123同步 2011-11-7 新增折扣分类。 2011-10-24 同步hao123.com首页时间、天气的显示方式。 2011-10-14 新增实用工具、彩票、音乐、小游戏聚合分类。 2011-9-30 重新整理了分类。 2011-5-8 增加电影分类,自动调用wz123.net电影数据。修复军事、旅游、酷站链接名。 2011-4-2 增加连续剧分类,自动调用hao123.com连续剧数据。 2011-4-1 改进天气自动调用weather.com.cn数据。 2011-1-10 增加设计、微博分类,同步分类排序。 2011-1-10 同步天气预报数据,自动获取IP显示城市天气。 2010-11-8 增加笑话分类,同步分类排序。 2010-11-7 修改163与126邮箱登录自动跳转官网,修复子目录返回首页链接。 2010-10-20 最新同步团购分类。 2010-7-28 最新同步hao123.com清新绿风格。 2010-3-5 应广大站长需要,再次提供HTML版本下载, 2010-1-15 同步hao123分类顺序,最新更新wz123.net职业与爱好分类。 2010-1-11 最新修复网站放在子目录上栏目页样式问题,有此问题的用户请下载最新版覆盖修复。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flybirding10011

谢谢支持啊999

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值