HBuilder mui登录和访问控制教程
mui中提供了登录的模板页,但是对于登录后各个页面的访问控制,刷新等并没有官方的推荐方案。我在这里简单说一种初级的解决方案吧,肯定有不足指出,欢迎批评指正。
第一节中创建移动APP项目的时候选择的是"mui项目",只引入了默认的js和css等文件,没有登录模板。要使用默认登录模板,可以创建的时候选择"mui登录模板"。现在创建一个名为muiLogin的"mui登录模板"项目:
![这里写图片描述](https://www.2cto.com/uploadfile/Collfiles/20170703/20170703092655224.png)
可以看到这次多了不少东西。通过manifest.json可以发现,入口文件时login.html,我们就从login.html开始。
从plusReady函数开始看起。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
<code><code><code><code>$.plusReady(function() {
plus.screen.lockOrientation(
"portrait-primary"
);
var settings = app.getSettings();
var state = app.getState();
var mainPage = $.preload({
"id"
:
'main'
,
"url"
:
'main.html'
});
var main_loaded_flag =
false
;
mainPage.addEventListener(
"loaded"
,function () {
main_loaded_flag =
true
;
});
var toMain = function() {
//使用定时器的原因:
//可能执行太快,main页面loaded事件尚未触发就执行自定义事件,此时必然会失败
var id = setInterval(function () {
if
(main_loaded_flag){
clearInterval(id);
$.fire(mainPage,
'show'
,
null
);
mainPage.show(
"pop-in"
);
}
},
20
);
};
//检查 "登录状态/锁屏状态" 开始
if
(settings.autoLogin && state.token && settings.gestures) {
$.openWindow({
url:
'unlock.html'
,
id:
'unlock'
,
show: {
aniShow:
'pop-in'
},
waiting: {
autoShow:
false
}
});
}
else
if
(settings.autoLogin && state.token) {
toMain();
}
else
{
app.setState(
null
);
//第三方登录
var authBtns = [
'qihoo'
,
'weixin'
,
'sinaweibo'
,
'qq'
];
//配置业务支持的第三方登录
var auths = {};
//...
}
}
</code></code></code></code>
|
先通过.preload预加载了main.html(就是mui,这是个闭包函数,mui作为参数$传进来的,详情百度JavaScript 闭包)。
toMain跳转主页面更新用户信息
然后是一个跳转到主页面的toMain函数,可以看到这里监听了main页面的loaded事件,当main加载完毕后,这里就将标志向量main_loaded_flag置为true,toMain中循环判断这个变量,当这里为true时,触发main的show事件,然后在main中,show事件的响应函数从app.getState()中读取用户名,显示在界面。这就完成了用户登录后主界面的用户名显示。
app.getState和app.setState
上面用到了app.getState(),这是定义在js/app.js中的,不妨去看下都做了什么。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<code><code><code><code><code>
/**
* 获取当前状态
**/
owner.getState = function() {
var stateText = localStorage.getItem(
'$state'
) ||
"{}"
;
return
JSON.parse(stateText);
};
/**
* 设置当前状态
**/
owner.setState = function(state) {
state = state || {};
localStorage.setItem(
'$state'
, JSON.stringify(state));
};
</code></code></code></code></code>
|
可以看到这两个是对localStorage的存取做了封装,是一个字典对象,这是个很不错的想法,可以将用户登录后的所有状态信息记录在state里面,包括用户信息,是否自动登录,用户余额,订单列表页的最新和最旧ID等都保存下来,用户注销后直接把state置为null就可以了,再次登录后再设置state。
上面的登录就是这样做的,登录成功后保存用户信息在state里面,然后触发涉及用户的main页面的事件,main页面里自定义事件的响应函数可以从state里读取信息并更新。
登录部分
登录这里先判断了是否运行自动登录以及是否设置了手势解锁。然后按情况决定是手势解锁还是直接登录或者显示登录界面。
点击登录按钮后,会调用app的login函数验证登录信息,验证正确就会调用toMain跳转到主页面。
访问控制
登陆部分很明了,但是大部分app是允许用户在不登录的情况下浏览部分页面的,如果用户访问的页面需要登录再自动跳转到登录页面。
这里就需要对登录验证做个封装,毕竟每次验证页面的时候,都从state里面判断一下用户是否登录了,以及是否允许自动登录,自动登录是否成功,是否显示登录界面是件很麻烦的事。
我们希望达到这种效果,如果用户点击
"我的"页面,通过以下代码自动进行访问控制:
1
2
3
4
5
6
7
8
9
|
<code><code><code><code><code><code><code>mui(
'#my'
)[
0
].addEventListener(
'tap'
,function(){
app.loginRequired(function(){
mui.openWindow({
url:
'my.html'
,
id:
'my'
});
});
});
</code></code></code></code></code></code></code>
|
只多了一行:
app.loginRequired,如果某个页面需要登录才能访问,就把登录后执行的代码作为回调函数传给
app.loginRequired,由它进行自动登录和登录不成功的跳转。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<code><code><code><code><code><code><code><code><code><code>
/**
* 要求登陆后才能执行回调函数
* @param {Object} callback 已登录或自动登录成功执行,否则跳转到登录界面
*/
owner.loginRequired=function(callback){
var state=owner.getState();
if
(state.isLogin){
//已登录,直接执行
callback();
}
else
{
owner.tryAutoLogin(function(data){
if
(data.Code==
1
){
//自动登录成功则执行回调函数
callback();
}
else
{
//自动登录失败,显示登录页面
var v=plus.webview.getWebviewById(
'login'
);
if
(!v){
mui.toast(
'error:cannot find login'
);
}
else
{
v.show(
'slide-in-right'
,
300
);
}
}
});
}
};
</code></code></code></code></code></code></code></code></code></code>
|
为了确保上面能找到登录页面,需要先预加载login页面,由于主页面是main,不再是login了,可以在main里面预加载login.html,然后这里就会找到login的webview
看到里面调用了一个
tryAutoLogin的自动登录函数,这个函数尝试用保存在state中的上次登录信息自动ajax请求服务器登录。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<code><code><code><code><code><code><code><code><code><code><code><code>
/**
* 尝试自动登录
* @param {Function} callback 回调函数,接收一个字典参数data,data.Code>0表示登录成功
*/
owner.tryAutoLogin=function (callback){
var state=owner.getState();
if
(state.isLogin){
callback({Code:
1
});
return
;
}
var user=JSON.parse(localStorage.getItem(
'$user'
));
//需要在登录或注册成功时将用户信息保存在localStorage中
var settings=owner.getSettings();
if
(settings.autoLogin&&user&&user.name) {
owner.login(user,callback);
}
else
{
callback({Code:-
1
});
}
}
</code></code></code></code></code></code></code></code></code></code></code></code>
|
tryAutoLogin的主要工作就是判断是否允许自动登录,如果允许就调用login方法尝试登录,并将回调函数也传递过去。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
<code><code><code><code><code><code><code><code><code><code><code><code><code>
/**
* 用户登录
**/
owner.login = function(loginInfo, callback) {
callback = callback || $.noop;
loginInfo.Method=
'Login'
;
//告诉服务器执行哪个函数
$.ajax(owner.server,{
//服务器地址
data:loginInfo,
success:function(data){
if
(data.Code==
1
){
plus.nativeUI.toast(
'登录成功'
);
var state=owner.defaultState;
//登录后用默认State覆盖现有的State
state.isLogin=
true
;
//标记已登录
state.user=data.Data;
//保存用户信息
owner.setState(state);
//保存登录信息
localStorage.setItem(
'$user'
, JSON.stringify(loginInfo));
//通知资金变动页面刷新
var moneyChange=plus.webview.getWebviewById(
'moneyChange'
);
if
(moneyChange){
mui.fire(moneyChange,
'show'
);
}
//通知其他用户相关页面更新
}
callback(data);
},
error:function(msg){
callback({
Code:-
3
,
Msg:
'无法连接到服务器'
});
}
});
};
</code></code></code></code></code></code></code></code></code></code></code></code></code>
|
login函数中有一句是defaultState,这个就是存储的默认用户状态,用户注销再次登录后就应该用这个替换上次用户的状态。防止信息错乱。
通过以上三个函数,就完成了页面登录的自动验证和访问控制,使得整体逻辑比较清晰,代码如有bug欢迎指正。