视图跳转(二)

关联事件

View.js 在执行视图跳转时,将按顺序执行如下动作:
  1. 1.
    同步触发 Viewbeforechange 事件
  2. 2.
    异步触发 当前活动视图 的 leave 事件
  3. 3.
    同步触发 目标视图 的 beforeenter 事件
  4. 4.
    隐藏当前活动视图,展现目标视图
  5. 5.
    同步触发 目标视图 的布局动作
  6. 6.
    同步触发 Viewchange 事件
  7. 7.
    同步触发 目标视图 的 ready 事件
  8. 8.
    同步触发 目标视图 的 enter 事件
  9. 9.
    同步触发 目标视图 的 afterenter 事件
  10. 10.
    更新视图容器上标记的活动视图信息
  11. 11.
    异步触发 Viewafterchange 事件
附加在 window 上的全局变量 View,以及每个 View 的实例,均是事件驱动的,均支持API: 1. 添加事件监听:on(evtName: string, handle: Function) 2. 移除事件监听:off(evtName: string, handle: Function) 3. 发起事件:fire(evtName: string, evtData?: any)
假定我们当前处于视图 A ,对于浏览路径:A → B 及如下事件监听:
init.js
1
var viewA = View.ofId("A"),
2
viewB = View.ofId("B");
3
4
var log = function(msg){
5
return function(){
6
console.log(msg);
7
};
8
};
9
10
View.on("beforechange", log("View: beforechange"));
11
View.on("change", log("View: change"));
12
View.on("afterchange", log("View: afterchange"));
13
14
viewA.on("leave", log("A: leave"));
15
viewB.on("beforeenter", log("B: beforeenter"));
16
viewB.on("ready", log("B: ready"));/* ready 事件仅在视图第一次进入时触发 */
17
viewB.on("enter", log("B: enter"));
18
viewB.on("afterenter", log("B: afterenter"));
Copied!
在切换至视图 B 后,我们将会得到下面的结果
事件触发顺序
View.js 预置的这些事件,是为了提供干预入口,使得开发者能够尽可能地找到贴切、恰当的时机执行程序任务。
通常来讲:
  1. 1.
    实例的 ready 事件,由于只在视图第一次进入时触发,多用于实现不需要反复进行的数据加载
  2. 2.
    实例的 enter 事件,多用于实现 “每次进入视图均重新加载、渲染数据”
  3. 3.
    实例的 leave, beforeenterafterenter,多用于 “重置页面内容,或准备页面环境”
  4. 4.
    Viewbeforechange, changeafterchange,多用于 “实现视图跳转动画,或执行其它宏观处理”

跳转目标

View.js 当前支持如下几种跳转目标:
  1. 1.
    视图ID
  2. 2.
    视图名称
  3. 3.
    视图实例(1.7.0+ 可用)
  4. 4.
    伪视图
  5. 5.
    外部链接地址
例如:
action.js
1
/**
2
* 以“压入堆栈”方式跳转至 default 命名空间下,ID 为 targetView 的视图
3
* 等同于 View.navTo("targetView", "default");
4
*
5
* 跳转目标:视图
6
*/
7
View.navTo("targetView");
8
9
/**
10
* 以“压入堆栈”方式跳转至 my-namespace 命名空间下,ID 为 targetView 的视图
11
* 跳转目标:视图
12
*
13
* 不同命名空间下可以声明相同ID的视图
14
*/
15
View.navTo("targetView", "my-namespace");
16
17
/**
18
* 以“压入堆栈”方式跳转至 my-namespace 命名空间下,ID 为 targetView 的视图
19
* 跳转目标:视图
20
*
21
* 不同命名空间下可以声明相同ID的视图
22
*/
23
View.navTo(View.ofId("targetView", "my-namespace"));
24
25
/**
26
* 以“切换栈顶”方式跳转至 default 命名空间下,ID 为 targetView 的视图,
27
* 并使用 params 关键字和 options 关键字传递参数
28
*
29
* 跳转目标:视图
30
*/
31
View.changeTo("targetView", {
32
/**
33
* params 为预留关键字,代表 视图参数。
34
* 视图参数可以传递任意类型的数据,但在视图刷新后丢失。
35
*/
36
params: {
37
"attr1": 1,
38
"obj": document.body,
39
"callback": function(data){
40
//do something with data
41
}
42
},
43
44
/**
45
* options 为预留关键字,代表 视图选项。
46
* 视图选项只能传递字符串类型的数据,页面刷新后参数仍然存在。
47
*/
48
options: {
49
"token": "token123"
50
}
51
});
52
53
/**
54
* 跳转目标:伪视图
55
*
56
* 支持的伪视图:
57
* 1) :default-view - 默认视图
58
* 2) :back - 上一个视图
59
* 3) :forward - 下一个视图
60
*
61
* View.changeTo() 仅支持伪视图:":default-view"
62
*/
63
View.navTo(":default-view");
64
65
/**
66
* 跳转目标:视图名称
67
*
68
* 符号:“~” 用于告诉 View.js 后边跟随的,是视图的名称
69
*
70
* View.changeTo() 同样支持按相同的语法进行跳转
71
*/
72
View.navTo("~viewName");
73
74
/**
75
* 跳转目标:外部链接
76
*
77
* 符号:“@” 用于告诉 View.js 后边跟随的,是外部链接地址
78
* 当跳转目标以 http,https 或 ftp 开头时,将自动识别为外部链接,不需要 "@" 符号
79
*
80
* View.changeTo() 同样支持按相同的语法跳转至外部链接
81
*/
82
View.navTo("@http://view-js.com");
83
84
/**
85
* 跳转目标:外部链接
86
*
87
* 如果跳转前的 URL 为 "http://domain/path/to/html/main.html",
88
* 跳转后的 URL 将为 "http://domain/path/to/html/sub/another.html"
89
*/
90
View.changeTo("@sub/another.html");
Copied!

跳转拦截

1.7.0 开始,View.js 支持开发者通过添加拦截器的方式,在宏观层面拦截视图跳转动作。例如:
1
/**
2
* 添加视图跳转拦截器
3
* 拦截器通过返回 true 或 false 告知 View.js 是否继续执行视图跳转动作
4
*/
5
View.addSwitchInterceptor(function(meta){
6
if(user.isLogined())
7
return true;
8
9
toast("请登录");
10
//...
11
12
return false;
13
});
Copied!
如果添加了多个拦截器,View.js 将按添加顺序顺序执行拦截器。如果上一个拦截器返回 false,下一个拦截器不会继续执行。

跳转效果优化

由于视图跳转完成的,只是活动视图DOM骨架的切换。而开发者一般在视图进入时才开始加载数据,所以会呈现出 “页面结构先变化,而后才填充数据” 的非原子性展示效果。
为了缓解这一不友好的体验,从 1.7.0 开始,View.js 允许开发者在进入视图前预先执行异步请求,在得到数据后再执行视图跳转动作。
例如:
商品详情
商品列表
1
var view = View.ofId("goods-detail");
2
3
/**
4
* 商品详情 视图使用该API描述自己所需要的数据的获取方式。
5
* 其它视图则使用该视图中由 View.js 创建的标准 fetchData()
6
* 方法执行数据加载动作。
7
*
8
* resolve:由 View.js 提供,供开发者执行的,用于告知 View.js 数据加载完成的方法;
9
* reject:由 View.js 提供,供开发者执行的,用于告知 Viewjs 数据加载失败的方法。
10
*/
11
view.setDataFetchAction(function(resolve, reject){
12
var goodsId = view.seekParameter("goods-id");
13
14
/* 加载商品详情 */
15
var promise1 = new Promise(function(_resolve, _reject){
16
callApi("get-goods-detail", {
17
id: "GOODS1",
18
19
onsuccess: function(data){
20
_resolve(data);
21
},
22
onerror: function(err){
23
_reject(err);
24
}
25
})
26
});
27
28
/* 加载商品评论 */
29
var promise2 = new Promise(function(_resolve, _reject){
30
callApi("get-goods-comments", {
31
id: "GOODS1",
32
33
onsuccess: function(data){
34
_resolve(data);
35
},
36
onerror: function(err){
37
_reject(err);
38
}
39
})
40
});
41
42
/* 数据加载成功或失败后通知 View.js */
43
Promise.all([promise1, promise2]).then(resolve, reject);
44
});
45
46
47
/* 视图进入后,根据传入的数据渲染界面,不再执行网络加载,从而带来完整性体验 */
48
view.on("enter", function(){
49
/* 参数由 商品列表 界面传入 */
50
var datas = view.getParameter("preloadedDatas");
51
52
var goodsDetal = datas[0],
53
goodsComments = dats[1];
54
55
/* 呈现商品详情 */
56
showGoodsDetail(goosdDetail);
57
58
/* 呈现商品评论 */
59
showGoodsComments(goodsComments);
60
});
Copied!
1
var view = View.ofId("goods-list");
2
3
/* 商品详情的入口 */
4
var goods1Obj = view.find(".list .detail[data-id=GOODS1]");
5
6
/**
7
* 进入 商品详情 视图。
8
* 进入前,预先加载 商品详情 所需要的数据。
9
*/
10
goods1Obj.addEventListener("click", function(){
11
var targetView = View.ofId("goods-detail");
12
13
/**
14
* 加载数据(数据的加载方法由目标视图自行描述)
15
*/
16
loading.show();
17
var thenable = targetView.fetchData();
18
thenable.then(function(datas){/* 数据加载成功 */
19
loading.hide();
20
21
/* 将数据传入 商品详情 视图 */
22
View.navTo(targetView, {
23
preloadedDatas: datas
24
});
25
}, function(err){/* 数据加载失败 */
26
loading.hide();
27
28
/* 提示错误后停留在 商品列表 视图 */
29
toast(err);
30
});
31
});
Copied!

开发调测

当进行视图切换时,View.js 将在 web 控制台中实时输出跳转信息,包括:
  1. 1.
    跳转方式(压入堆栈、替换堆栈,还是弹出栈顶)
  2. 2.
    跳转传参
  3. 3.
    视图的当前浏览位置
例如:
开发调测1
开发调测2
此外,View.js 提供了API:View.ifCanGoBack() 来检索当前是否处于栈顶,例如:
开发调测3
开发调测4
当浏览位置处于栈顶时,View.back() 以及 data-view-rel=':back' 在执行时将没有任何反应,开发者可以通过API: View.setNoViewToNavBackAction(action: Function) 设定此时的表现,亦即: “没有更多页面可回退时将要执行的动作” 。例如:
init.js
1
/**
2
* 当执行 View.back() 或 点击 data-view-rel=':back' 元素时,
3
* 如果没有更早的浏览信息,浏览器将弹窗提示 “2”。
4
*/
5
View.setNoViewToNavBackAction(function(){
6
alert(2);
7
});
Copied!

其它能力

视图跳转在完成活动视图切换的同时,还具有如下功能:
  1. 1.
    设置视图跳转动画
  2. 2.
    在视图之间传递参数
  3. 3.
    动态设置浏览器标题
我们将在后边的章节中分别介绍。
Last modified 1yr ago