1. 基本的html结构
<div ct-data-role="page" id="index"></div>
具有ct-data-role="page"属性的元素代表一个基本的页面, id属性唯一标识这个页面,需要注意的是具有ct-data-role="page"属性的元素必须为body的子元素,不能是任意级别的元素。还需要注意的是html中至少含有一个Page的结构来代表第一个显示的页面内容
2. 初始化应用
import CtMobile from "ctmobile";
const Router = {
index: {
url: "/static/html/index.html",
component: import(/* webpackChunkName: "index" */ "../pages/index"),
},
info: {
url: "/static/html/info.html",
component: import(/* webpackChunkName: "info" */ "../pages/info"),
},
about: {
url: "/static/html/about.html",
component: import(/* webpackChunkName: "about" */ "../pages/about"),
},
};
const App = CtMobile.CtMobileFactory.create({
supportCordova: false,
linkCaptureReload: false,
router: Router,
});
详细参数解释请参考属性配置。
3. 路由
在初始化应用的代码中需要配置router选项,router是一个对象,对象的键需要和基本结构中id属性的值保持一致,值为一个对象,有两个属性url和component
- url 代表这个页面引用的html片段地址,片段就是一个Page的基本结构
- component
返回一个Promise对象,代表这个页面的逻辑处理类,Promise中返回的对象应该是继承了Page类的一个子类。
如用Webpack进行开发的时候可以定义成
component属性可以不进行设置,如果不设置component属性,那么框架会认为url载入的页面只进行显示,不进行逻辑处理。component: import(/* webpackChunkName: "about" */ "../pages/about")
4. 编写页面对应的Page
import CtMobile from 'ctmobile';
export default class extends CtMobile.Page {
constructor(ctmobile, id) {
super(ctmobile, id);
}
/**
* @override
*/
pageCreate(){
console.log('页面初始化');
}
/**
* @override
*/
pageShow() {
console.log('page的DOM显示时调用');
}
/**
* @override
*/
pageBeforeDestory(){
console.log('page的DOM销毁之前调用');
}
}
编写一个类继承自Page类即可完成一个页面的定义,其中构造函数会有两个参数,ctmobile和id,其中ctmobile代表整个App的实例,id代表Page基本机构中的id属性值。 其中pageCreate,pageShow和pageBeforeDestory是Page的生命周期函数,更多生命周期函数请参考Page的生命周期
5. 跳转到一个新页面
跳转到一个新页面可以有两种方式
配置方式
<a ct-pageId="info">跳转到info页面</a>
在a标签中使用ct-pageId属性就可以跳转到一个新的页面,其中ct-pageId的值为Page基本机构中id的值。
api方式 使用App.startPage方法跳转到一个新的页面,其中App对象是初始化应用后的返回值,如果是在Page类中可以通过this.getCtMobile()方法获取
this.getCtMobile().startPage("/static/html/info.html?pageId=info");
需要注意的是html路径后会有一个pageId的参数,参数值是Page基本结构中id的值
6. 页面间传递参数
- 字符串方式
- 使用ct-parameter属性
<a ct-pageId="about" ct-parameter="&a=1&b=2"></a>
- 使用api方式
this.getCtMobile().startPage("/static/html/info.html?pageId=info&a=1&b=2");
- 使用ct-parameter属性
内存方式 通过调用Page类的setRequest方法进行参数传递,在目标页面调用Page类的getRequest方法获取参数,使用内存方式的好处是可以在页面之间传递任何数据类型的数据,缺点是如果直接刷新此页的话不会保存上一回的数据,不像字符串方式可以永久保留参数的值
A.js
<!-- 向B.html传递参数 --> this.setRequest('requestCode',{a:1,b:2}); this.ctmobile.startPage("/static/html/b.html?pageId=b");
B.js
pageAfterShow() { <!-- 获取A.html传递过来的参数 --> const parameter = JSON.stringify(this.getRequest()); console.log('parameter',parameter); }
需要注意的是需要在pageAfterShow的回调中调用getRequest方法,只要pageAfterShow函数被调用,之后在任何地方在调用getRequest方法都可以获取到参数。
7. 带有返回值的页面
页面的基本结构中加入ct-page-mode="result"或者ct-page-mode="singleInstanceResult"属性
举个例子,当前有两个页面index.html,PopUpDialog.html两个页面。index.html中有个弹出按钮,点击按钮弹出PopUpDialog页面
index.html定义
<div ct-data-role="page" id="index">
<a ct-pageId="PopUpDialog">弹出PopUpDialog</a>
<div class="resultText">PopUpDialog的返回值<div>
</div>
index.js定义
import CtMobile from 'ctmobile';
import $ from 'jquery';
export default class extends CtMobile.Page{
constructor(ctmobile,id){
super(ctmobile,id);
}
/**
* override
*/
pageCreate() {
}
/**
* PopUpDialog返回时触发
* override
*/
pageResult(e, resultCode, bundle) {
console.log("resultCode", resultCode, "bundle", JSON.stringify(bundle));
alert(`resultCode:${resultCode}\r\nbundle:${JSON.stringify(bundle)}`);
}
}
PopUpDialog的html定义
<div ct-data-role="page" id="PopUpDialog" ct-data-mode="result">
<button class="result">返回</button>
</div>
或者
<div ct-data-role="page" id="PopUpDialog" ct-data-mode="singleInstanceResult">
<button class="result">返回</button>
</div>
PopUpDialog.js定义
import CtMobile from 'ctmobile';
import $ from 'jquery';
export default class extends CtMobile.Page {
constructor(ctmobile,id){
super(ctmobile,id);
}
/**
* override
*/
pageCreate() {
const $btnEL = this.getPageJO().find(' .result');
$btnEl.on('click' , () => {
this.setResult('PopUpDialog', {a: 1, b: 2});
this.over();
});
}
}
index.html需要做的是在index.js中重写pageResult方法,此方法在PopUpDialog返回或手动调用finish方法后被触发,pageResult的有三个参数e,resultCode,bundle,其中resultCode用来区分不同的来源,bundle是被带回来的值。 PopUpDialog.html需要做的是在PopUpDialog.js中调用this.setResult(resultCode,bundle);方法来设置返回的值,在调用this.finish();方法后页面关闭。
带有返回值的页面使用场景一般分为两种
- 多对一 a.html,b.html,c.html...都弹出d.html
- 一对多 a.html弹出b.html,c.html,d.html...
在多对一的情况下可以通过setRequest方法把父页面的标志传递过去。
在一对多的情况下可以通过pageResult方法的requestCode区分不同来源。
8. Page的启动模式
在页面的基本结构中设置ct-data-mode属性值即可,框架一共支持5中启动模式
standard(默认) 多例模式
多例模式就是通过配置或者api跳转到此页面的时候都会建立一个新的实例,所谓新的实例就是Dom和Dom对应的Page类都会是新的。
single 单例模式(当点击返回时会销毁)
和Android中single一样,举个例子,加入有如下的页面开发顺序 : index.html -> a.html -> b.html -> c.html -> d.html -> b.html 如果把b.html的ct-data-mode设置为single,那么执行上述页面顺序后, 历史栈中当前是 index.html -> a.html -> b.html 也是删除了c.html和d.html,删除的同事也会调用相应的生命周期函数。 但是如果在b.html中点击返回那么b.html还是会销毁的。
singleInstance 完全的单例模式(在任何时候都不会被销毁)
完全单例就是在任何时候都不会被销毁且只有一个实例存在。
result 带有返回值的(可以向父页面带回返回值)
singleInstanceResult 带有返回值的完全单例(不会被销毁,可以向父页面带回返回值)
和result一样只是实例不会被销毁。
9. Page的生命周期
Page一共有10个生命周期函数
10. 页面转场效果
在页面的基本结构中设置ct-data-transition属性值即可,框架一共支持13种页面的过度效果
- slideleft-从右到左(overlay)
- slideright-从左到右(overlay)
- slideup-从下到上(overlay)
- slidedown-从上到下(overlay)
- wxslideleft-类似于微信的从右到左
- wxslideright-类似于微信的从左到右
- wxslideup-类似于微信的从下到上
- wxslidedown-类似于微信的从上到下
- pushslideleft-从右到左(push)
- pushslideright-从左到右(push)
- pushslideup-从下到上(push)
- pushslidedown-从上到下(push)
- material-Android Material的风格
11. 广播(borasdcast)
借鉴了Android中Borasdcast概念,为Page之间的数据传递提供了一系列功能,广播分为有序和无序,可以通过配置和api两种方式实现广播。
通过配置注册 在基本机构中加入ct-data-intentfilter-action,ct-data-intentfilter-categorys属性进行注册
<div ct-page-role="page" id="index" ct-data-intentfilter-action="actionCode" ct-data-intentfilter-categorys="c1,c2" ct-data-intentfilter-priority="0" ></div>
Page中重写pageReceiver方法
import CtMobile from 'ctmobile'; export default class extends CtMobile.Page { constructor(ctmobile,id){ super(ctmobile,id); } /** * @override */ pageReceiver(intent) { console.log(intent); } }
通过api注册
import CtMobile from 'ctmobile'; export default class extends CtMobile.Page { constructor(ctmobile,id){ super(ctmobile,id); } onRegisterReceiver(intent) { console.log(JSON.stringify(intent)); } /** * @override */ pageCreate() { this.onRegisterReceiver = this.onRegisterReceiver.bind(this); // 注册borasdcast this.ctmobile.registerReceiver({ action: 'actionCode', priority: 0, categorys: ['c1','c2'] }, this.onRegisterReceiver); } }
- 发送无序广播
在Page类中调用CtMobile的sendBroadcast方法
this.ctmobile.sendBroadcast({ action: 'actionCode', categorys: ['c1','c2'], bundle: { a: 1, b: 2 } });
- 发送有序广播
在Page类中调用CtMobile的sendOrderedBroadcast方法
this.ctmobile.sendOrderedBroadcast({ action: 'actionCode', categorys: ['c1','c2'], bundle: { a: 1, b: 2 } });
- 有序广播
- 通知的优先级
有序广播的通知是有顺序的,这个顺序是有priority这个属性决定的,priority越大越先被通知到,越小越晚被通知到。
使用配置设置priority
使用api注册设置priority<div ct-page-role="page" id="index" ct-data-intentfilter-priority="0" ></div>
// 注册borasdcast this.ctmobile.registerReceiver({ action: 'actionCode', priority: 0, categorys: ['c1','c2'] }, this.onRegisterReceiver);
- 向后传递参数和终止传递
- 通知的优先级
有序广播的通知是有顺序的,这个顺序是有priority这个属性决定的,priority越大越先被通知到,越小越晚被通知到。
使用配置设置priority
在有序广播的回调函数中会有2个参数intent和opt,其中intent是通知传递的参数,opt是个对象,其中有2个方法,putExtras和next,其中putExtras设置向下传递的参数,这些参数是合并在一起的。只有调用next方法才向下进行传递。
- 通知的分类(categorys)
在注册广播的时候除了Action之外,还可以定义多个category,categorys可以认为是一个二级标题,作用是用来对Action进行细粒度的定义。
12. 其他功能
是否增加历史 如果不想让新跳转的页面增加到历史栈中,可以设置ct-reload属性为true来阻止浏览器增加历史。
<a ct-pageId="a" ct-reload="true">a.html</a>
this.ctmobile.startPage('/static/html/a.html?pageId=a',{ reload:true });
比如index.html -> a.html,那么历史栈中只有a.html
a标签不交由框架处理 有些时候我们不希望让框架来处理a标签的行为,此时就可以在a标签上加入ct-data-ajax="false"
ajax内容预加载
<div ct-data-role="page" id="index"> <a ct-pageId="a" ct-data-preload="true">into a.html</a> <a ct-pageId="b" ct-data-preload="true">into b.html</a> <a ct-pageId="c" ct-data-preload="true">into c.html</a> <a ct-pageId="d" ct-data-preload="true">into d.html</a> <a ct-pageId="e" ct-data-preload="true">into e.html</a> </div>
框架会在初始化的时候就加载a-e.html的内容 如果a-e.html中还有需要预加载的页面,那框架还会进行预加载 每个页面只会被预加载一次,如果预加载完了以后就不会在被预加载了。
使用配置进行页面的返回
<div ct-data-role="page" id="about"> <header> <a class="ct-back-icon" ct-data-rel="back"></a> </header> </div>