原生JS实现全屏切换以及导航栏滑动隐藏及显示——重构前
分类:
IT文章
•
2024-03-07 19:41:24
2017-1-15更新:原生JS实现全屏切换以及导航栏滑动隐藏及显示——修改,这篇文章中的代码解决了bug。
思路分析:
- 向后滚动鼠标滚轮,页面向下全屏切换;向前滚动滚轮,页面向上全屏切换。切换过程为动画效果。
- 第一屏时,导航栏固定在页面顶部,切换到第二屏时,导航条向左滑动隐藏。切换回第一屏时,导航栏向右滑动显示。
- 页面显示的不是第一平时,当鼠标指针滑动到页面的头部区域,导航栏向右滑出;鼠标指针移出头部区域时,导航栏向左滑动隐藏。
- 当视口尺寸小于768px时,切换页面不隐藏导航条,但是导航条的项目要隐藏,通过点击按钮来显示和隐藏项目。
本篇代码是重构前的代码。
HTML代码:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <meta http-equiv="X-UA-Compatible" content="IE=edge">
6 <meta name="viewport" content="width=device-width, initial-scale=1">
7 <title>全屏滚动</title>
8
9 <style type="text/css">
10 </style>
11 </head>
12 <body>
13 <header id="nav-head">
14 <nav id="nav">
15 <div id="navbar-header">
16 <div id="logo-box">
17 <!--<img >-->
18 Fogwind
19 </div>
20 <button id="navbar-toggle" type="button">
21 <span class="icon-bar"></span>
22 <span class="icon-bar"></span>
23 <span class="icon-bar"></span>
24 </button>
25 </div>
26 <!--
27 <button >
28 <
29 </button>
30 -->
31 <ul id="navbar-item" class="navbar-item-block navbar-item-none">
32 <hr id="navbar-item-border" />
33 <li class="navbar-list">
34 <a href="http://www.battlenet.com.cn/zh/">战网1</a>
35 </li>
36 <li class="navbar-list">
37 <a href="http://www.battlenet.com.cn/zh/">战网2</a>
38 </li>
39 <li class="navbar-list">
40 <a href="http://www.battlenet.com.cn/zh/">战网3</a>
41 </li>
42 <li class="navbar-list">
43 <a href="http://www.battlenet.com.cn/zh/">战网4</a>
44 </li>
45 </ul>
46
47
48 </nav>
49 </header>
50
51 <!--全屏滚动-->
52 <div id="full-page">
53 <div id="page-box">
54 <div id="page-one" class="page"></div>
55 <div id="page-two" class="page"></div>
56 <div id="page-three" class="page"></div>
57 <div id="page-four" class="page"></div>
58 </div>
59 </div>
60 <script>
61 </script>
62 </body>
63 </html>
View Code
CSS代码:
1 *{
2 margin: 0;
3 padding: 0;
4 }
5 html,body{
6 height: 100%;
7 }
8 a{
9 text-decoration: none;
10 }
11 /********************导航栏样式**********************/
12 #nav-head{
13 height: 50px;
14 width: 100%;
15 position: absolute;
16 background: transparent;
17 z-index: 900;
18 }
19 #nav{
20 background-color: #222;
21 height: auto;
22 position: fixed;
23 width: 100%;
24 top: 0;
25 z-index: 1000;
26 }
27
28 #logo-box{
29 float: left;
30 height: 50px;
31 padding: 15px 15px;
32 margin-left: -15px;
33 font-size: 18px;
34 line-height: 20px;
35 color: #9d9d9d;
36 }
37 /*当log-brand是图片时*/
38 #logo-brand{
39 display: block;
40 max-height: 35px;
41 }
42 /*导航栏右边按钮中的三道杠*/
43 .icon-bar{
44 display: block;
45 width: 22px;
46 height: 2px;
47 border-radius: 1px;
48 background-color: #fff;
49 }
50 #navbar-toggle .icon-bar + .icon-bar{
51 margin-top: 4px;
52 }
53 /*导航栏列表ul*/
54 #navbar-item{
55 list-style: none;
56 }
57 #navbar-item-border{/*ul上部分割线,大屏时不显示*/
58 border: 0;
59 height: 1px;
60 background-color: #333;
61 }
62 .navbar-item-block{
63 display: block;
64 overflow: hidden;
65 }
66
67 .navbar-list a{
68 display: block;
69 color: #9d9d9d;
70 padding: 15px 15px;
71 line-height: 20px;
72 }
73 .navbar-list a:hover{
74 color: #fff;
75 }
76 /*向左隐藏导航栏按钮
77 #navbar-slip {
78 float: right;
79 }*/
80 /*大屏时*/
81 @media (min- 768px) {
82 #navbar-header{
83 float: left;
84 height: 50px;
85 padding: 0 15px;
86 }
87 #navbar-item-border{
88 display: none;
89 }
90 .navbar-list{
91 float: left;
92 }
93
94 #navbar-toggle{
95 display: none;
96 }
97 }
98 /*中小屏时*/
99 @media (max- 767px) {
100 #navbar-header{
101 display: block;
102 overflow: hidden;
103 height: 50px;
104 padding: 0 15px;
105 }
106 #navbar-toggle{
107 float: right;
108 background-color: transparent;
109 border: 1px solid #333;
110 border-radius: 4px;
111 padding: 9px 10px;
112 margin-top: 8px;
113 margin-bottom: 8px;
114 }
115 #navbar-toggle:hover{
116 background-color: #333;
117 }
118
119 .navbar-item-none{
120 display: none;
121 }
122
123 /*#navbar-slip{
124 display: none;
125 }*/
126 }
127
128 /*************************全屏滚动样式**************************/
129 #full-page{
130 height: 100%;
131 position: relative;
132 overflow: hidden;
133 }
134 #page-box{
135 height: 100%;
136 width: 100%;
137 position: absolute;
138 }
139 .page{
140 height: 100%;
141 }
142 #page-one{
143 background-color: #6495ED;
144 }
145 #page-two{
146 background-color: #B8860B;
147 }
148 #page-three{
149 background-color: #8470FF;
150 }
151 #page-four{
152 background-color: #D87093;
153 }
View Code
这其中最关键的是html,body{height: 100%},这条样式可以初始化body的高度为视口高度,即使它里面没有内容。媒体查询规定了小屏幕下的样式。导航栏用了固定定位,全屏切换的每个页面用div包裹,这个div绝对定位,通过控制其top属性实现全屏切换。
1 var bool = true;//存储导航栏的状态,显示时为true,隐藏时为false
2
3 //跨浏览器的添加事件的函数
4 function addHandler(element, type, handler) {
5 if(element.addEventListener) {
6 element.addEventListener(type, handler, false);
7 } else if(element.attachEvent) {
8 element.attachEvent('on' + type, handler);
9 } else {
10 element['on' + type] = handler;
11 }
12 }
13
14 //跨浏览器的添加mousewheel事件的函数
15 function addMouseWheelEvent(element,func) {
16
17 if(typeof element.onmousewheel == "object") {
18
19 addHandler(element,"mousewheel",func);
20 }
21 if(typeof element.onmousewheel == "undefined") {
22 //alert(1);
23 //兼容Firefox
24 addHandler(element,"DOMMouseScroll",func);
25 }
26 }
27 /**********中小屏显示/隐藏导航栏中项目的代码***********/
28 var navbarbtn = document.getElementById("navbar-toggle");
29 //保存navbarbtn被点击了几次
30 navbarbtn.count = 0;
31 navbarbtn.onclick = function() {
32 var navbaritem = document.getElementById("navbar-item");
33 if(navbarbtn.count === 0) {
34 //第一次点击时显示项目
35 navbaritem.className = "navbar-item-block";
36 navbarbtn.count++;
37 } else {
38 //第二次点击时隐藏项目,并重置navbarbtn.count
39 navbaritem.className = "navbar-item-none navbar-item-block";
40 navbarbtn.count = 0;
41 }
42
43 };
44
45 /*************向左隐藏导航条,向右显示导航条****************/
46 var nav = document.getElementById('nav');
47 //分别用来保存导航栏开始滑动和结束滑动的时间
48 //利用两者差值来判断动画效果是否完成
49 nav.startDate = 0;
50 nav.stopDate = 0;
51 //动画效果完成所需的时间
52 nav.t = 300;
53
54 //向左隐藏
55 function navSlideLeft() {
56 if(nav.navmove) {
57 clearInterval(nav.navmove);
58 }
59
60 //获取nav的计算样式表
61 var computedStyle;
62 if(document.defaultView.getComputedStyle) { //DOM 2标准方法
63 computedStyle = document.defaultView.getComputedStyle(nav,null);
64 } else {
65 computedStyle = nav.currentStyle;//兼容IE方法
66 }
67
68 var width = parseInt(computedStyle.width), speed = width/(nav.t/10), left = parseInt(computedStyle.left);
69 //IE中computedStyle.left为auto
70 //下面的if语句用来兼容IE
71 if(!Boolean(left)) {
72 left = 0;
73 }
74 //如果nav没有向左隐藏,执行向左隐藏代码
75 //alert(width);
76 if(left > -width) {
77
78 nav.startDate = new Date();
79 nav.navmove = setInterval(function() {
80 nav.stopDate = new Date();
81 if(nav.stopDate - nav.startDate < nav.t) {
82 left += -speed;
83 //nav.style.left += left + 'px';
84 } else {
85 left = -width;
86 //nav.style.left = left + 'px';
87 clearInterval(nav.navmove);
88 }
89 nav.style.left = left + 'px';
90 },10);
91 } else {
92 return;
93 }
94 }
95
96 function navSlideRight() {
97 if(nav.navmove) {
98 clearInterval(nav.navmove);
99 }
100 //获取nav的计算样式表
101 var computedStyle;
102 if(document.defaultView.getComputedStyle) { //DOM 2标准方法
103 computedStyle = document.defaultView.getComputedStyle(nav,null);
104 } else {
105 computedStyle = nav.currentStyle;//兼容IE方法
106 }
107
108 var width = parseInt(computedStyle.width), speed = width/(nav.t/10), left = parseInt(computedStyle.left);
109
110 //如果nav没有向左隐藏,执行向左隐藏代码
111 if(left < 0) {
112
113 nav.startDate = new Date();
114 nav.navmove = setInterval(function() {
115 nav.stopDate = new Date();
116 if(nav.stopDate - nav.startDate < nav.t) {
117 left += speed;
118 //nav.style.left += left + 'px';
119 } else {
120 left = 0;
121 //nav.style.left = left + 'px';
122 clearInterval(nav.navmove);
123 }
124 nav.style.left = left + 'px';
125 },10);
126 } else {
127 return;
128 }
129 }
130
131 /*全屏滚动代码*/
132 var pageBox = document.getElementById('page-box');
133 if(document.defaultView.getComputedStyle) { //DOM 2标准方法
134 pageBox.computedStyle = document.defaultView.getComputedStyle(pageBox,null);
135 } else {
136 pageBox.computedStyle = pageBox.currentStyle;//兼容IE方法
137 }
138 pageBox.startDate = 0;
139 pageBox.stopDate = 0;
140 pageBox.t = 300;
141
142 //获取有几屏
143 pageBox.pageChildren = pageBox.getElementsByTagName('div').length;
144
145 //切换计数
146 pageBox.num = 1;
147
148 //超时调用ID,优化mousewheel事件,防止连续触发
149 pageBox.mousewheelTimer = null;
150
151 function pageSlideUp(num) {
152 if(pageBox.pageScroll) {
153 clearInterval(pageBox.pageScroll);
154 }
155 var height = parseInt(pageBox.computedStyle.height);
156 var top = parseInt(pageBox.computedStyle.top);
157 var speed = height/(pageBox.t/10);
158 pageBox.startDate = new Date();
159 pageBox.pageScroll = setInterval(function() {
160 pageBox.stopDate = new Date();
161 if(pageBox.stopDate - pageBox.startDate < pageBox.t) {
162 top += -speed;
163 } else {
164 top = -height*num;
165 clearInterval(pageBox.pageScroll);
166 }
167 pageBox.style.top = top + "px";
168 },10);
169 }
170
171 function pageSlideDown(num) {
172 if(pageBox.pageScroll) {
173 clearInterval(pageBox.pageScroll);
174 }
175 var height = parseInt(pageBox.computedStyle.height);
176 var top = parseInt(pageBox.computedStyle.top);
177 var speed = height/(pageBox.t/10);
178 pageBox.startDate = new Date();
179 pageBox.pageScroll = setInterval(function() {
180 pageBox.stopDate = new Date();
181 if(pageBox.stopDate - pageBox.startDate < pageBox.t) {
182 top += speed;
183 } else {
184 top = -height*num;
185 clearInterval(pageBox.pageScroll);
186 }
187 pageBox.style.top = top + "px";
188 },10);
189 }
190
191
192 function mouseWheelListener(event) {
193
194 event = event || window.event;
195 //获取滚动方向
196 var wheelDelta;
197 if(event.wheelDelta) {
198 wheelDelta = event.wheelDelta;
199 } else {
200
201 wheelDelta = -event.detail;//兼容Firefox
202 }
203 //alert(wheelDelta);
204 //通过超时调用优化滚动事件
205 if(pageBox.mousewheelTimer) {
206 clearTimeout(pageBox.mousewheelTimer);
207 }
208 //当连续两次滚动鼠标滚轮的时间间隔小于pageBox.t时,不触发滚动效果
209 if((pageBox.stopDate - pageBox.startDate > 0) && (pageBox.stopDate - pageBox.startDate < pageBox.t)) {
210 //console.log(pageBox.stopDate - pageBox.startDate);
211 return;
212 }
213 //mousewheel事件与mouseover事件的时间间隔小于nav.t时,不触发事件,防止事件冲突。
214 var nowtime = new Date();
215 if(nowtime - navhead.leaveDate<nav.t) {
216 return;
217
218 }
219
220 //当滚轮向后滚动时
221 if(wheelDelta < 0) {
222 if(pageBox.num <= pageBox.pageChildren - 1) {
223 pageBox.mousewheelTimer = setTimeout(pageSlideUp(pageBox.num),20);
224 pageBox.num++;//最后等于pageBox.pageChildren,这里为4
225 //console.log(pageBox.num);
226 } else {
227 return;
228 }
229 } else {//当滚轮向前滚动时
230 if(pageBox.num <= pageBox.pageChildren && pageBox.num > 1) {
231 pageBox.num--;
232 pageBox.mousewheelTimer = setTimeout(pageSlideDown(pageBox.num-1),20);
233 //console.log(pageBox.num);
234 } else {
235 pageBox.num = 1;
236 return;
237 }
238 }
239
240 //隐藏导航条
241 /*
242 if(parseInt(pageBox.computedStyle.width) > 768 && event.clientY > 50) {
243 if(pageBox.num != 1 && bool)
244
245 navSlideLeft();
246 bool = false;
247 }
248 if(pageBox.num == 1 && !bool) {
249 navSlideRight();
250 bool = true;
251 } */
252
253 //解决导航条进出切换bug,主要是两次事件触发的时间间隔小于动画时间所致
254 //因为动画效果由三个事件触发:mousewheel,navhead的mouseover和pageBox的mouseover,事件之间有冲突
255 //包括代码中的所有时间间隔的判断都是为了解决此bug
256 //导航栏高度固定为50px
257 if(parseInt(pageBox.computedStyle.width) > 768 && event.clientY > 50) {
258 if(pageBox.num == 2 && bool) {
259 navSlideLeft();
260 bool = false;
261 }
262 if(pageBox.num == 1 && !bool) {
263 navSlideRight();
264 bool = true;
265 }
266 }
267 }
268
269 //给document添加鼠标滚动事件
270 addMouseWheelEvent(document,mouseWheelListener);
271
272 //保存超时调用ID,优化resize事件,防止连续触发
273 var resizeTimer = null;
274 //视口宽度小于768时,导航条不隐藏,大于768时才隐藏
275 //同时保证全屏切换时,每一屏的高度始终等于视口高度
276 window.onresize = function() {
277 if (resizeTimer) {
278 clearTimeout(resizeTimer)
279 }
280 resizeTimer = setTimeout(function() {
281 pageBox.style.top = (-parseInt(pageBox.computedStyle.height)*(pageBox.num-1)) + "px";
282
283 if(parseInt(pageBox.computedStyle.width) < 768) {
284 nav.style.left = '0px';
285 }
286 if(parseInt(pageBox.computedStyle.width) >= 768 && pageBox.num != 1) {
287 //这里有点小bug,最小化再最大化,鼠标滑过头部区域后导航条不消失
288 nav.style.left = (-parseInt(pageBox.computedStyle.width)) + 'px';
289 bool = false;
290 }
291
292
293 },20);
294 };
295
296 var navhead = document.getElementById('nav-head');
297 navhead.overDate = 0;
298 navhead.leaveDate = 0;
299 navhead.onmouseover = function(event) {
300 event = event || window.event;
301 event.target = event.srcElement || event.target;
302
303 //防止navhead的子元素触发事件(也可以阻止事件冒泡)
304 if(event.target.nodeName != this.nodeName) {//换成判断id
305 return;
306 }
307 if(pageBox.num == 1 || parseInt(pageBox.computedStyle.width) < 768 ) {
308 return;
309 }
310
311 navhead.overDate = new Date();
312 //console.log(navhead.overDate - navhead.leaveDate);
313 //这里的时间间隔判断会产生一个bug
314 //当切换到下一屏时,如果指针足够快划入头部区域,导航条不出现,要滑出来等至少0.3s,才行
315 //如果你足够快,让指针在头部与页面之间来回切换,导航条始终不出现。
316 //下面pageBox的mouseover事件同理
317 if((navhead.overDate - navhead.leaveDate) > pageBox.t) {
318 if(!bool) {
319 navSlideRight();
320 bool = true;
321 }
322 }
323 /**
324
325
326
327 //console.log(navhead.overDate - navhead.leaveDate);
328 if((navhead.overDate - navhead.leaveDate) > pageBox.t) {
329 if(parseInt(pageBox.computedStyle.width) > 768 && pageBox.num != 1) {
330 if(parseInt(nav.style.left) < 0) {
331 navSlideRight();
332 }
333
334
335 }
336 }**/
337 };
338
339 pageBox.onmouseover = function(event) {
340 if(pageBox.num == 1 || parseInt(pageBox.computedStyle.width) < 768 ) {
341 return;
342 }
343 //console.log(123);
344 event = event || window.event;
345 navhead.leaveDate = new Date();
346 //console.log(navhead.leaveDate.getTime());
347 if((navhead.leaveDate - navhead.overDate) > pageBox.t) {
348 if(parseInt(pageBox.computedStyle.width) > 768 && pageBox.num != 1) {
349 if(bool) {
350 navSlideLeft();
351 bool = false;
352 }
353 }
354 if(parseInt(pageBox.computedStyle.width) > 768 && pageBox.num == 1) {
355 if(!bool) {
356 navSlideRight();
357 bool = true;
358 }
359 }
360 }
361 };