2017-1-15更新:原生JS实现全屏切换以及导航栏滑动隐藏及显示——修改,这篇文章中的代码解决了bug。

思路分析:

  1. 向后滚动鼠标滚轮,页面向下全屏切换;向前滚动滚轮,页面向上全屏切换。切换过程为动画效果。
  2. 第一屏时,导航栏固定在页面顶部,切换到第二屏时,导航条向左滑动隐藏。切换回第一屏时,导航栏向右滑动显示。
  3. 页面显示的不是第一平时,当鼠标指针滑动到页面的头部区域,导航栏向右滑出;鼠标指针移出头部区域时,导航栏向左滑动隐藏。
  4. 当视口尺寸小于768px时,切换页面不隐藏导航条,但是导航条的项目要隐藏,通过点击按钮来显示和隐藏项目。

本篇代码是重构前的代码。

HTML代码:

 <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>全屏滚动</title> <style type="text/css">
</style>
</head>
<body>
<header id="nav-head">
<nav id="nav">
<div id="navbar-header">
<div id="logo-box">
<!--<img id="logo-brand" src="乔巴.jpg" />-->
Fogwind
</div>
<button id="navbar-toggle" type="button">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<!--
<button id="navbar-slip" type="button">
&lt;
</button>
-->
<ul id="navbar-item" class="navbar-item-block navbar-item-none">
<hr id="navbar-item-border" />
<li class="navbar-list">
<a href="http://www.battlenet.com.cn/zh/">战网1</a>
</li>
<li class="navbar-list">
<a href="http://www.battlenet.com.cn/zh/">战网2</a>
</li>
<li class="navbar-list">
<a href="http://www.battlenet.com.cn/zh/">战网3</a>
</li>
<li class="navbar-list">
<a href="http://www.battlenet.com.cn/zh/">战网4</a>
</li>
</ul> </nav>
</header> <!--全屏滚动-->
<div id="full-page">
<div id="page-box">
<div id="page-one" class="page"></div>
<div id="page-two" class="page"></div>
<div id="page-three" class="page"></div>
<div id="page-four" class="page"></div>
</div>
</div>
<script>
</script>
</body>
</html>

CSS代码:

 *{
margin:;
padding:;
}
html,body{
height: 100%;
}
a{
text-decoration: none;
}
/********************导航栏样式**********************/
#nav-head{
height: 50px;
width: 100%;
position: absolute;
background: transparent;
z-index:;
}
#nav{
background-color: #222;
height: auto;
position: fixed;
width: 100%;
top:;
z-index:;
} #logo-box{
float: left;
height: 50px;
padding: 15px 15px;
margin-left: -15px;
font-size: 18px;
line-height: 20px;
color: #9d9d9d;
}
/*当log-brand是图片时*/
#logo-brand{
display: block;
max-height: 35px;
}
/*导航栏右边按钮中的三道杠*/
.icon-bar{
display: block;
width: 22px;
height: 2px;
border-radius: 1px;
background-color: #fff;
}
#navbar-toggle .icon-bar + .icon-bar{
margin-top: 4px;
}
/*导航栏列表ul*/
#navbar-item{
list-style: none;
}
#navbar-item-border{/*ul上部分割线,大屏时不显示*/
border:;
height: 1px;
background-color: #333;
}
.navbar-item-block{
display: block;
overflow: hidden;
} .navbar-list a{
display: block;
color: #9d9d9d;
padding: 15px 15px;
line-height: 20px;
}
.navbar-list a:hover{
color: #fff;
}
/*向左隐藏导航栏按钮
#navbar-slip {
float: right;
}*/
/*大屏时*/
@media (min-width: 768px) {
#navbar-header{
float: left;
height: 50px;
padding: 0 15px;
}
#navbar-item-border{
display: none;
}
.navbar-list{
float: left;
} #navbar-toggle{
display: none;
}
}
/*中小屏时*/
@media (max-width: 767px) {
#navbar-header{
display: block;
overflow: hidden;
height: 50px;
padding: 0 15px;
}
#navbar-toggle{
float: right;
background-color: transparent;
border: 1px solid #333;
border-radius: 4px;
padding: 9px 10px;
margin-top: 8px;
margin-bottom: 8px;
}
#navbar-toggle:hover{
background-color: #333;
} .navbar-item-none{
display: none;
} /*#navbar-slip{
display: none;
}*/
} /*************************全屏滚动样式**************************/
#full-page{
height: 100%;
position: relative;
overflow: hidden;
}
#page-box{
height: 100%;
width: 100%;
position: absolute;
}
.page{
height: 100%;
}
#page-one{
background-color: #6495ED;
}
#page-two{
background-color: #B8860B;
}
#page-three{
background-color: #8470FF;
}
#page-four{
background-color: #D87093;
}

CSS代码参考了Bootstrap的代码。

这其中最关键的是html,body{height: 100%},这条样式可以初始化body的高度为视口高度,即使它里面没有内容。媒体查询规定了小屏幕下的样式。导航栏用了固定定位,全屏切换的每个页面用div包裹,这个div绝对定位,通过控制其top属性实现全屏切换。

JS代码:

   var bool = true;//存储导航栏的状态,显示时为true,隐藏时为false

   //跨浏览器的添加事件的函数
function addHandler(element, type, handler) {
if(element.addEventListener) {
element.addEventListener(type, handler, false);
} else if(element.attachEvent) {
element.attachEvent('on' + type, handler);
} else {
element['on' + type] = handler;
}
} //跨浏览器的添加mousewheel事件的函数
function addMouseWheelEvent(element,func) { if(typeof element.onmousewheel == "object") { addHandler(element,"mousewheel",func);
}
if(typeof element.onmousewheel == "undefined") {
//alert(1);
//兼容Firefox
addHandler(element,"DOMMouseScroll",func);
}
}
/**********中小屏显示/隐藏导航栏中项目的代码***********/
var navbarbtn = document.getElementById("navbar-toggle");
//保存navbarbtn被点击了几次
navbarbtn.count = 0;
navbarbtn.onclick = function() {
var navbaritem = document.getElementById("navbar-item");
if(navbarbtn.count === 0) {
//第一次点击时显示项目
navbaritem.className = "navbar-item-block";
navbarbtn.count++;
} else {
//第二次点击时隐藏项目,并重置navbarbtn.count
navbaritem.className = "navbar-item-none navbar-item-block";
navbarbtn.count = 0;
} }; /*************向左隐藏导航条,向右显示导航条****************/
var nav = document.getElementById('nav');
//分别用来保存导航栏开始滑动和结束滑动的时间
//利用两者差值来判断动画效果是否完成
nav.startDate = 0;
nav.stopDate = 0;
//动画效果完成所需的时间
nav.t = 300; //向左隐藏
function navSlideLeft() {
if(nav.navmove) {
clearInterval(nav.navmove);
} //获取nav的计算样式表
var computedStyle;
if(document.defaultView.getComputedStyle) { //DOM 2标准方法
computedStyle = document.defaultView.getComputedStyle(nav,null);
} else {
computedStyle = nav.currentStyle;//兼容IE方法
} var width = parseInt(computedStyle.width), speed = width/(nav.t/10), left = parseInt(computedStyle.left);
//IE中computedStyle.left为auto
//下面的if语句用来兼容IE
if(!Boolean(left)) {
left = 0;
}
//如果nav没有向左隐藏,执行向左隐藏代码
//alert(width);
if(left > -width) { nav.startDate = new Date();
nav.navmove = setInterval(function() {
nav.stopDate = new Date();
if(nav.stopDate - nav.startDate < nav.t) {
left += -speed;
//nav.style.left += left + 'px';
} else {
left = -width;
//nav.style.left = left + 'px';
clearInterval(nav.navmove);
}
nav.style.left = left + 'px';
},10);
} else {
return;
}
} function navSlideRight() {
if(nav.navmove) {
clearInterval(nav.navmove);
}
//获取nav的计算样式表
var computedStyle;
if(document.defaultView.getComputedStyle) { //DOM 2标准方法
computedStyle = document.defaultView.getComputedStyle(nav,null);
} else {
computedStyle = nav.currentStyle;//兼容IE方法
} var width = parseInt(computedStyle.width), speed = width/(nav.t/10), left = parseInt(computedStyle.left); //如果nav没有向左隐藏,执行向左隐藏代码
if(left < 0) { nav.startDate = new Date();
nav.navmove = setInterval(function() {
nav.stopDate = new Date();
if(nav.stopDate - nav.startDate < nav.t) {
left += speed;
//nav.style.left += left + 'px';
} else {
left = 0;
//nav.style.left = left + 'px';
clearInterval(nav.navmove);
}
nav.style.left = left + 'px';
},10);
} else {
return;
}
} /*全屏滚动代码*/
var pageBox = document.getElementById('page-box');
if(document.defaultView.getComputedStyle) { //DOM 2标准方法
pageBox.computedStyle = document.defaultView.getComputedStyle(pageBox,null);
} else {
pageBox.computedStyle = pageBox.currentStyle;//兼容IE方法
}
pageBox.startDate = 0;
pageBox.stopDate = 0;
pageBox.t = 300; //获取有几屏
pageBox.pageChildren = pageBox.getElementsByTagName('div').length; //切换计数
pageBox.num = 1; //超时调用ID,优化mousewheel事件,防止连续触发
pageBox.mousewheelTimer = null; function pageSlideUp(num) {
if(pageBox.pageScroll) {
clearInterval(pageBox.pageScroll);
}
var height = parseInt(pageBox.computedStyle.height);
var top = parseInt(pageBox.computedStyle.top);
var speed = height/(pageBox.t/10);
pageBox.startDate = new Date();
pageBox.pageScroll = setInterval(function() {
pageBox.stopDate = new Date();
if(pageBox.stopDate - pageBox.startDate < pageBox.t) {
top += -speed;
} else {
top = -height*num;
clearInterval(pageBox.pageScroll);
}
pageBox.style.top = top + "px";
},10);
} function pageSlideDown(num) {
if(pageBox.pageScroll) {
clearInterval(pageBox.pageScroll);
}
var height = parseInt(pageBox.computedStyle.height);
var top = parseInt(pageBox.computedStyle.top);
var speed = height/(pageBox.t/10);
pageBox.startDate = new Date();
pageBox.pageScroll = setInterval(function() {
pageBox.stopDate = new Date();
if(pageBox.stopDate - pageBox.startDate < pageBox.t) {
top += speed;
} else {
top = -height*num;
clearInterval(pageBox.pageScroll);
}
pageBox.style.top = top + "px";
},10);
} function mouseWheelListener(event) { event = event || window.event;
//获取滚动方向
var wheelDelta;
if(event.wheelDelta) {
wheelDelta = event.wheelDelta;
} else { wheelDelta = -event.detail;//兼容Firefox
}
//alert(wheelDelta);
//通过超时调用优化滚动事件
if(pageBox.mousewheelTimer) {
clearTimeout(pageBox.mousewheelTimer);
}
//当连续两次滚动鼠标滚轮的时间间隔小于pageBox.t时,不触发滚动效果
if((pageBox.stopDate - pageBox.startDate > 0) && (pageBox.stopDate - pageBox.startDate < pageBox.t)) {
//console.log(pageBox.stopDate - pageBox.startDate);
return;
}
//mousewheel事件与mouseover事件的时间间隔小于nav.t时,不触发事件,防止事件冲突。
var nowtime = new Date();
if(nowtime - navhead.leaveDate<nav.t) {
return; } //当滚轮向后滚动时
if(wheelDelta < 0) {
if(pageBox.num <= pageBox.pageChildren - 1) {
pageBox.mousewheelTimer = setTimeout(pageSlideUp(pageBox.num),20);
pageBox.num++;//最后等于pageBox.pageChildren,这里为4
//console.log(pageBox.num);
} else {
return;
}
} else {//当滚轮向前滚动时
if(pageBox.num <= pageBox.pageChildren && pageBox.num > 1) {
pageBox.num--;
pageBox.mousewheelTimer = setTimeout(pageSlideDown(pageBox.num-1),20);
//console.log(pageBox.num);
} else {
pageBox.num = 1;
return;
}
} //隐藏导航条
/*
if(parseInt(pageBox.computedStyle.width) > 768 && event.clientY > 50) {
if(pageBox.num != 1 && bool) navSlideLeft();
bool = false;
}
if(pageBox.num == 1 && !bool) {
navSlideRight();
bool = true;
} */ //解决导航条进出切换bug,主要是两次事件触发的时间间隔小于动画时间所致
//因为动画效果由三个事件触发:mousewheel,navhead的mouseover和pageBox的mouseover,事件之间有冲突
//包括代码中的所有时间间隔的判断都是为了解决此bug
//导航栏高度固定为50px
if(parseInt(pageBox.computedStyle.width) > 768 && event.clientY > 50) {
if(pageBox.num == 2 && bool) {
navSlideLeft();
bool = false;
}
if(pageBox.num == 1 && !bool) {
navSlideRight();
bool = true;
}
}
} //给document添加鼠标滚动事件
addMouseWheelEvent(document,mouseWheelListener); //保存超时调用ID,优化resize事件,防止连续触发
var resizeTimer = null;
//视口宽度小于768时,导航条不隐藏,大于768时才隐藏
//同时保证全屏切换时,每一屏的高度始终等于视口高度
window.onresize = function() {
if (resizeTimer) {
clearTimeout(resizeTimer)
}
resizeTimer = setTimeout(function() {
pageBox.style.top = (-parseInt(pageBox.computedStyle.height)*(pageBox.num-1)) + "px"; if(parseInt(pageBox.computedStyle.width) < 768) {
nav.style.left = '0px';
}
if(parseInt(pageBox.computedStyle.width) >= 768 && pageBox.num != 1) {
//这里有点小bug,最小化再最大化,鼠标滑过头部区域后导航条不消失
nav.style.left = (-parseInt(pageBox.computedStyle.width)) + 'px';
bool = false;
} },20);
}; var navhead = document.getElementById('nav-head');
navhead.overDate = 0;
navhead.leaveDate = 0;
navhead.onmouseover = function(event) {
event = event || window.event;
event.target = event.srcElement || event.target; //防止navhead的子元素触发事件(也可以阻止事件冒泡)
if(event.target.nodeName != this.nodeName) {//换成判断id
return;
}
if(pageBox.num == 1 || parseInt(pageBox.computedStyle.width) < 768 ) {
return;
} navhead.overDate = new Date();
//console.log(navhead.overDate - navhead.leaveDate);
//这里的时间间隔判断会产生一个bug
//当切换到下一屏时,如果指针足够快划入头部区域,导航条不出现,要滑出来等至少0.3s,才行
//如果你足够快,让指针在头部与页面之间来回切换,导航条始终不出现。
//下面pageBox的mouseover事件同理
if((navhead.overDate - navhead.leaveDate) > pageBox.t) {
if(!bool) {
navSlideRight();
bool = true;
}
}
/** //console.log(navhead.overDate - navhead.leaveDate);
if((navhead.overDate - navhead.leaveDate) > pageBox.t) {
if(parseInt(pageBox.computedStyle.width) > 768 && pageBox.num != 1) {
if(parseInt(nav.style.left) < 0) {
navSlideRight();
} }
}**/
}; pageBox.onmouseover = function(event) {
if(pageBox.num == 1 || parseInt(pageBox.computedStyle.width) < 768 ) {
return;
}
//console.log(123);
event = event || window.event;
navhead.leaveDate = new Date();
//console.log(navhead.leaveDate.getTime());
if((navhead.leaveDate - navhead.overDate) > pageBox.t) {
if(parseInt(pageBox.computedStyle.width) > 768 && pageBox.num != 1) {
if(bool) {
navSlideLeft();
bool = false;
}
}
if(parseInt(pageBox.computedStyle.width) > 768 && pageBox.num == 1) {
if(!bool) {
navSlideRight();
bool = true;
}
}
}
};

JS代码比较乱,后期还要用面向对象思想重构。这里主要说说写的过程中遇到的一些问题及bug。

1、以前写轮播图时,首先想到的都是用位置判断动画效果有没有完成,这容易导致轮播效果不稳定。比如走着走着速度越来越快、图片不是整张显示而是跨张显示或者图片不见了等等,这些bug的产生与Javascript的定时机制有关。所以这次直接以前一次动画函数与当前动画函数的调用时间差来判断动画效果是否完成。

2、鼠标滚动事件在不同浏览器之间的兼容性。参考我以前的文章:mousewheel事件的兼容方法

3、获取元素计算样式表的方法,主要是跨浏览器的兼容。这里碰到一个问题,一个元素的CSS属性有很多,获取到的计算样式表中各个属性的值在不同浏览器中差别很大,比如我没有明确设置绝对定位的<nav>元素的left属性,在获取到的计算样式表中,Chrome浏览器中left属性为0px,Firefox和IE中则为auto,需要初始化为0px。所以在以后的项目中,如果要获取元素的计算样式表,一定要注意浏览器之间的差异。

4、通过超时调用优化mousewheel事件和resize事件,防止连续触发。

5、如果使用了超时调用或间歇调用一定注意记得清除,特别是实现动画效果的时候。

6、在这个项目中导航条的显示/隐藏有三个事件可以触发,为了解决事件之间的冲突,使用了各个事件之间的触发时间差与动画完成所需时间做判断条件,等动画效果完成才能触发事件,否则不触发。这虽然解决了事件冲突的bug,也带来了一些其他的小bug。比如,先最小化再最大化视口,鼠标滑过头部区域后导航条不消失;当切换到下一屏时,如果指针足够快划入头部区域,导航条不出现,要滑出来等至少0.3s,才可以(其实这两个bug都是同一个原因导致的,就是两次事件的触发时间差小于动画完成所需的时间)。这些bug我暂时还不知道怎么解决,不过与事件冲突比起来,还不是特别严重,也不影响使用。

暂时就想到这么多,接下来对代码进行重构,以便后期好维护。

原生JS实现全屏切换以及导航栏滑动隐藏及显示——重构前的更多相关文章

  1. 用原生JS实现爱奇艺首页导航栏

    以下是爱奇艺首页的一个导航栏,用原生js写的,静态页面效果如下: 代码如下: <html> <head> <title>爱奇艺</title> < ...

  2. 炫酷:一句代码实现标题栏、导航栏滑动隐藏。ByeBurger库的使用和实现

    本文已授权微信公众号:鸿洋(hongyangAndroid)原创首发. 其实上周五的时候已经发过一篇文章.基本实现了底部导航栏隐藏的效果.但是使用起来可能不是很实用.因为之前我实现的方式是继承了系统的 ...

  3. 基于Ascensor.js全屏切换页面插件

    今天给大家分享一款基于Ascensor.js全屏切换页面插件,这款实例 适用浏览器:IE8.360.FireFox.Chrome.Safari.Opera.傲游.搜狗.世界之窗.效果图如下: 在线预览 ...

  4. js实现网页全屏切换(平滑过渡),鼠标滚动切换

    实现效果为页面平滑过渡全屏切换,点击导航和鼠标滚动都可以切换. 效果图: html代码: <!DOCTYPE html> <html> <head lang=" ...

  5. jquery横向纵向鼠标滚轮全屏切换

    html <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF- ...

  6. jQuery插件开发——全屏切换插件

    这个插件包含三个部分:HTML结构.CSS代码和JS代码. HTML结构是固定的,结构如下: <!--全屏滚动--> <div class="fullpage-contai ...

  7. jQuery鼠标滚动垂直全屏切换代码

    体验效果:http://hovertree.com/texiao/jquery/68/ 源码下载:http://hovertree.com/h/bjaf/f643upc4.htm 代码如下: < ...

  8. jquery简单的大背景banner图片全屏切换

    详细内容请点击 这个是我初毕业刚进公司那会帮同事(同时也是同学)写的一个PC端的全屏图片切换效果,对于刚毕业的我来说写出来那会的喜悦之情是无法言表的,那时的我还是什么不懂的小白白,俗称菜鸟.个人网站上 ...

  9. fullpage.js jq全屏滚动插件

    fullPage.js和fullPage都能实现全屏滚动,二者区别是:fullPage.js需依赖于JQuery库,而fullPage不需要依赖任何一个js库,可以单独使用. (代码演示效果并且可以下 ...

随机推荐

  1. Partition1:新建分区表

    未分区的表,只能存储在一个FileGroup中:对Table进行分区后,每一个分区都存储在一个FileGroup,或分布式存储在不同的FileGroup中.对表进行分区的过程,是将逻辑上完整的一个表, ...

  2. 02.LoT.UI 前后台通用框架分解系列之——灵活的菜单栏

    LOT.UI分解系列汇总:http://www.cnblogs.com/dunitian/p/4822808.html#lotui LoT.UI开源地址如下:https://github.com/du ...

  3. Bootstrap 模态框(Modal)插件

    页面效果: html+js: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  4. 《Django By Example》第三章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:第三章滚烫出炉,大家请不要吐槽文中 ...

  5. Android数据加密之Base64编码算法

    前言: 前面学习总结了平时开发中遇见的各种数据加密方式,最终都会对加密后的二进制数据进行Base64编码,起到一种二次加密的效果,其实呢Base64从严格意义上来说的话不是一种加密算法,而是一种编码算 ...

  6. Android调用微信登陆、分享、支付

    前言:用了微信sdk各种痛苦,感觉比qq sdk调用麻烦多了,回调过于麻烦,还必须要在指定包名下的actvity进行回调,所以我在这里写一篇博客,有这个需求的朋友可以借鉴一下,以后自己别的项目有用到也 ...

  7. Phoenix综述(史上最全Phoenix中文文档)

    个人主页:http://www.linbingdong.com 简书地址:http://www.jianshu.com/users/6cb45a00b49c/latest_articles 网上关于P ...

  8. Android公共title的应用

    我们在开发Android应用中,写每一个页面的时候都会建一个title,不是写一个LinearLayout就是写一个RelativeLayout,久而久之就会觉得这样繁琐,尤其几个页面是只是标题不一样 ...

  9. 通过VMware的PowerCLI配置集群内指定主机的vMotion功能

    PowerCLI是VMware开发的基于微软(MSFT)的PowerShell的命令行管理vSphere的实现,因此在批量化操作方面CLI会减轻很多GUI环境下的繁琐重复劳作. 现有场景中有大量的物理 ...

  10. 如何使用SHOW WARNINGS?

    1.show warnings:显示上一个语句的错误.警告以及注意.如图: