其实官方已经给出详细解决方案: tab选项卡示例教程-基于subnview模式的原生tab(含底部凸起大图标)
但是官方的案例首页是写死的,并且图标是字体图标,不是图片,还有其他一些效果都和我们平时的需求不同,所以,我爱模板网对其进行了改良,下面是相关代码,具体就不解释了:
1、mainifest.json代码修改如下,主要就是将官方 mui tab底部凸起案例 的字体图标换成了图片:
01 |
"launchwebview" : {
|
02 |
"bottom" : "0px" ,
|
03 |
"background" : "#fff" ,
|
04 |
"subNViews" : [
|
05 |
{
|
06 |
"id" : "tabBar" ,
|
07 |
"styles" : {
|
08 |
"bottom" : "0px" ,
|
09 |
"left" : "0" ,
|
10 |
"height" : "50px" ,
|
11 |
"width" : "100%" ,
|
12 |
"backgroundColor" : "#fff"
|
13 |
},
|
14 |
"tags" : [
|
15 |
{
|
16 |
"tag" : "img" ,
|
17 |
"id" : "homeIcon" ,
|
18 |
"src" : "images/home_nor.png" ,
|
19 |
"position" : {
|
20 |
"top" : "4px" ,
|
21 |
"left" : "10%" ,
|
22 |
"width" : "25px" ,
|
23 |
"height" : "40px"
|
24 |
}
|
25 |
},{
|
26 |
"tag" : "img" ,
|
27 |
"id" : "scheduleIcon" ,
|
28 |
"src" : "images/schedule_nor.png" ,
|
29 |
"position" : {
|
30 |
"top" : "4px" ,
|
31 |
"left" : "30%" ,
|
32 |
"width" : "25px" ,
|
33 |
"height" : "40px"
|
34 |
}
|
35 |
},{
|
36 |
"tag" : "img" ,
|
37 |
"id" : "goodsIcon" ,
|
38 |
"src" : "images/goods_nor.png" ,
|
39 |
"position" : {
|
40 |
"top" : "4px" ,
|
41 |
"left" : "65%" ,
|
42 |
"width" : "25px" ,
|
43 |
"height" : "40px"
|
44 |
}
|
45 |
},{
|
46 |
"tag" : "img" ,
|
47 |
"id" : "mineIcon" ,
|
48 |
"src" : "images/mine_nor.png" ,
|
49 |
"position" : {
|
50 |
"top" : "4px" ,
|
51 |
"left" : "85%" ,
|
52 |
"width" : "25px" ,
|
53 |
"height" : "40px"
|
54 |
}
|
55 |
}
|
56 |
]
|
57 |
}
|
58 |
]
|
59 |
} |
001 |
var util = {
|
002 |
options: {
|
003 |
ACTIVE_SRC1: "images/home_click.png" ,
|
004 |
NORMAL_SRC1: "images/home_nor.png" ,
|
005 |
ACTIVE_SRC2: "images/schedule_click.png" ,
|
006 |
NORMAL_SRC2: "images/schedule_nor.png" ,
|
007 |
ACTIVE_SRC3: "images/goods_click.png" ,
|
008 |
NORMAL_SRC3: "images/goods_nor.png" ,
|
009 |
ACTIVE_SRC4: "images/mine_click.png" ,
|
010 |
NORMAL_SRC4: "images/mine_nor.png" ,
|
011 |
subpages: [{
|
012 |
url : 'pages/home.html' ,
|
013 |
id : 'home'
|
014 |
},{
|
015 |
url : 'pages/schedule.html' ,
|
016 |
id : 'schedule'
|
017 |
},{
|
018 |
url : 'pages/goods.html' ,
|
019 |
id : 'goods'
|
020 |
},{
|
021 |
url : 'pages/mine.html' ,
|
022 |
id : 'mine'
|
023 |
},]
|
024 |
},
|
025 |
/**
|
026 |
* 简单封装了绘制原生view控件的方法
|
027 |
* 绘制内容支持font(文本,字体图标),图片img , 矩形区域rect
|
028 |
*/
|
029 |
drawNative: function (id, styles, tags) {
|
030 |
var view = new plus.nativeObj.View(id, styles, tags);
|
031 |
return view;
|
032 |
},
|
033 |
/**
|
034 |
* 初始化首个tab窗口 和 创建子webview窗口
|
035 |
*/
|
036 |
initSubpage: function (aniShow) {
|
037 |
var subpage_style = {
|
038 |
top: 0,
|
039 |
bottom: 51
|
040 |
},
|
041 |
subpages = util.options.subpages,
|
042 |
self = plus.webview.currentWebview(),
|
043 |
temp = {};
|
044 |
//兼容安卓上添加titleNView 和 设置沉浸式模式会遮盖子webview内容
|
045 |
if (mui.os.android) {
|
046 |
if (plus.navigator.isImmersedStatusbar()) {
|
047 |
subpage_style.top += plus.navigator.getStatusbarHeight();
|
048 |
}
|
049 |
if (self.getTitleNView()) {
|
050 |
subpage_style.top += 40;
|
051 |
}
|
052 |
}
|
053 |
054 |
// 初始化第一个tab项为首次显示
|
055 |
temp[self.id] = "true" ;
|
056 |
mui.extend(aniShow, temp);
|
057 |
058 |
// 初始化绘制首个tab按钮
|
059 |
util.toggleNview(0);
|
060 |
061 |
//预加载所有子页面
|
062 |
for ( var i = 0, len = subpages.length; i < len; i++) {
|
063 |
if (!plus.webview.getWebviewById(subpages[i].id)) {
|
064 |
var sub = plus.webview.create(subpages[i].url, subpages[i].id, subpage_style);
|
065 |
//初始化隐藏
|
066 |
sub.hide();
|
067 |
// append到当前父webview
|
068 |
self.append(sub);
|
069 |
}
|
070 |
}
|
071 |
072 |
//初始化显示第一个子页面
|
073 |
plus.webview.show(plus.webview.getWebviewById(subpages[0].id));
|
074 |
075 |
},
|
076 |
/**
|
077 |
* 点击切换tab窗口
|
078 |
*/
|
079 |
changeSubpage: function (targetPage, activePage, aniShow) {
|
080 |
//若为iOS平台或非首次显示,则直接显示
|
081 |
if (mui.os.ios || aniShow[targetPage]) {
|
082 |
plus.webview.show(targetPage);
|
083 |
} else {
|
084 |
//否则,使用fade-in动画,且保存变量
|
085 |
var temp = {};
|
086 |
temp[targetPage] = "true" ;
|
087 |
mui.extend(aniShow, temp);
|
088 |
plus.webview.show(targetPage, "fade-in" , 300);
|
089 |
}
|
090 |
//隐藏当前 除了第一个父窗口
|
091 |
if (activePage !== plus.webview.getLaunchWebview()) {
|
092 |
plus.webview.hide(activePage);
|
093 |
}
|
094 |
},
|
095 |
/**
|
096 |
* 点击重绘底部tab (view控件)
|
097 |
*/
|
098 |
toggleNview: function (currIndex) {
|
099 |
// 重绘当前tag 包括icon和text,所以执行两个重绘操作
|
100 |
switch (currIndex){
|
101 |
case 0 :
|
102 |
util.updateSubNView(0, util.options.ACTIVE_SRC1);
|
103 |
util.updateSubNView(1, util.options.NORMAL_SRC2);
|
104 |
util.updateSubNView(2, util.options.NORMAL_SRC3);
|
105 |
util.updateSubNView(3, util.options.NORMAL_SRC4);
|
106 |
break ;
|
107 |
case 1 :
|
108 |
util.updateSubNView(0, util.options.NORMAL_SRC1);
|
109 |
util.updateSubNView(1, util.options.ACTIVE_SRC2);
|
110 |
util.updateSubNView(2, util.options.NORMAL_SRC3);
|
111 |
util.updateSubNView(3, util.options.NORMAL_SRC4);
|
112 |
break ;
|
113 |
case 2 :
|
114 |
util.updateSubNView(0, util.options.NORMAL_SRC1);
|
115 |
util.updateSubNView(1, util.options.NORMAL_SRC2);
|
116 |
util.updateSubNView(2, util.options.ACTIVE_SRC3);
|
117 |
util.updateSubNView(3, util.options.NORMAL_SRC4);
|
118 |
break ;
|
119 |
case 3 :
|
120 |
util.updateSubNView(0, util.options.NORMAL_SRC1);
|
121 |
util.updateSubNView(1, util.options.NORMAL_SRC2);
|
122 |
util.updateSubNView(2, util.options.NORMAL_SRC3);
|
123 |
util.updateSubNView(3, util.options.ACTIVE_SRC4);
|
124 |
break ;
|
125 |
}
|
126 |
},
|
127 |
/*
|
128 |
* 利用 plus.nativeObj.View 提供的 drawBitmap 方法更新 view 控件
|
129 |
*/
|
130 |
updateSubNView: function (currIndex, src) {
|
131 |
var self = plus.webview.currentWebview(),
|
132 |
nviewEvent = plus.nativeObj.View.getViewById( "tabBar" ), // 获取nview控件对象
|
133 |
nviewObj = self.getStyle().subNViews[0], // 获取nview对象的属性
|
134 |
currTag = nviewObj.tags[currIndex]; // 获取当前需重绘的tag
|
135 |
nviewEvent.drawBitmap(src, '' ,currTag.position, currTag.id);
|
136 |
}
|
137 |
}; |
001 |
<!DOCTYPE html> |
002 |
< html >
|
003 |
< head >
|
004 |
< meta charset = "UTF-8" >
|
005 |
< meta name = "viewport" content = "width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
|
006 |
< title >首页</ title >
|
007 |
< script src = "js/mui.min.js" ></ script >
|
008 |
< link href = "css/mui.min.css" rel = "stylesheet" />
|
009 |
< style >
|
010 |
html, |
011 |
body { |
012 |
background-color: #efeff4;
|
013 |
} |
014 |
015 |
.title { |
016 |
margin: 20px 15px 10px;
|
017 |
color: #6d6d72;
|
018 |
font-size: 15px;
|
019 |
padding-bottom: 51px;
|
020 |
} |
021 |
</ style >
|
022 |
</ head >
|
023 |
024 |
< body >
|
025 |
< script src = "js/util.js" ></ script >
|
026 |
< script type = "text/javascript" >
|
027 |
(function() {
|
028 |
mui.init({
|
029 |
swipeBack: true //启用右滑关闭功能
|
030 |
});
|
031 |
mui.plusReady(function() {
|
032 |
var self = plus.webview.currentWebview(),
|
033 |
leftPos = Math.ceil((window.innerWidth - 60) / 2); // 设置凸起大图标为水平居中
|
034 |
/**
|
035 |
* drawNativeIcon 绘制凸起圆,
|
036 |
* 实现原理:
|
037 |
* id为bg的tag 创建带边框的圆
|
038 |
* id为bg2的tag 创建白色矩形遮住圆下半部分,只显示凸起带边框部分
|
039 |
* id为iconBg的红色背景图
|
040 |
* id为icon的字体图标
|
041 |
* 注意创建先后顺序,创建越晚的层级越高
|
042 |
*/
|
043 |
var drawNativeIcon = util.drawNative('icon', {
|
044 |
bottom: '5px',
|
045 |
left: leftPos + 'px',
|
046 |
width: '60px',
|
047 |
height: '60px'
|
048 |
}, [{
|
049 |
tag: 'rect',
|
050 |
id: 'bg',
|
051 |
position: {
|
052 |
top: '1px',
|
053 |
left: '0px',
|
054 |
width: '100%',
|
055 |
height: '100%'
|
056 |
},
|
057 |
rectStyles: {
|
058 |
color: '#fff',
|
059 |
radius: '50%',
|
060 |
borderColor: '#ccc',
|
061 |
borderWidth: '1px'
|
062 |
}
|
063 |
}, {
|
064 |
tag: 'rect',
|
065 |
id: 'bg2',
|
066 |
position: {
|
067 |
bottom: '-0.5px',
|
068 |
left: '0px',
|
069 |
width: '100%',
|
070 |
height: '45px'
|
071 |
},
|
072 |
rectStyles: {
|
073 |
color: '#fff'
|
074 |
}
|
075 |
}, {
|
076 |
tag: 'rect',
|
077 |
id: 'iconBg',
|
078 |
position: {
|
079 |
top: '5px',
|
080 |
left: '5px',
|
081 |
width: '50px',
|
082 |
height: '50px'
|
083 |
},
|
084 |
rectStyles: {
|
085 |
color: '#0ab88e',
|
086 |
radius: '50%'
|
087 |
}
|
088 |
},{
|
089 |
tag: 'img',
|
090 |
id: 'icon',
|
091 |
position: {
|
092 |
top: '15px',
|
093 |
left: '15px',
|
094 |
width: '30px',
|
095 |
height: '30px'
|
096 |
},
|
097 |
src: 'images/icon_scan.png'
|
098 |
}]);
|
099 |
// 将绘制的凸起 append 到父webview中
|
100 |
self.append(drawNativeIcon);
|
101 |
102 |
103 |
//凸起圆的点击事件
|
104 |
var active_color = '#fff';
|
105 |
drawNativeIcon.addEventListener('click', function(e) {
|
106 |
mui.openWindow({
|
107 |
id : 'scan',
|
108 |
url : 'pages/scan.html'
|
109 |
})
|
110 |
});
|
111 |
// 中间凸起图标绘制及监听点击 完毕
|
112 |
113 |
// 创建子webview窗口 并初始化
|
114 |
var aniShow = {};
|
115 |
util.initSubpage(aniShow);
|
116 |
|
117 |
//初始化相关参数
|
118 |
var nview = plus.nativeObj.View.getViewById('tabBar'),
|
119 |
activePage = plus.webview.currentWebview(),
|
120 |
targetPage,
|
121 |
subpages = util.options.subpages,
|
122 |
pageW = window.innerWidth,
|
123 |
currIndex = 0;
|
124 |
|
125 |
/**
|
126 |
* 根据判断view控件点击位置判断切换的tab
|
127 |
*/
|
128 |
nview.addEventListener('click', function(e) {
|
129 |
var clientX = e.clientX;
|
130 |
if(clientX >= 0 && clientX <= parseInt(pageW * 0.25)) {
|
131 |
currIndex = 0;
|
132 |
} else if(clientX > parseInt(pageW * 0.25) && clientX <= parseInt(pageW * 0.45)) {
|
133 |
currIndex = 1;
|
134 |
} else if(clientX > parseInt(pageW * 0.45) && clientX <= parseInt(pageW * 0.8)) {
|
135 |
currIndex = 2;
|
136 |
} else {
|
137 |
currIndex = 3;
|
138 |
}
|
139 |
// 匹配对应tab窗口
|
140 |
if(plus.webview.getWebviewById(subpages[currIndex].id) == plus.webview.currentWebview()){
|
141 |
return;
|
142 |
}else{
|
143 |
targetPage = plus.webview.getWebviewById(subpages[currIndex].id);
|
144 |
}
|
145 |
146 |
//底部选项卡切换
|
147 |
util.toggleNview(currIndex);
|
148 |
// 子页面切换
|
149 |
util.changeSubpage(targetPage, activePage, aniShow);
|
150 |
//更新当前活跃的页面
|
151 |
activePage = targetPage;
|
152 |
153 |
});
|
154 |
});
|
155 |
})();
|
156 |
</ script >
|
157 |
</ body >
|
158 |
</ html >
|
nativeTab_5imoban
注:代码注释非常详细,可以对比着官方demo进行修改,也可以直接使用我爱模板网修改的demo,将图片替换即可。