JavaScript实战之带收放动画效果的导航菜单


Posted in Javascript onAugust 16, 2016

虽然有很多插件可用,但为了共同提高,我做了一系列JavaScript实战系列的实例,分享给大家,前辈们若有好的建议,请务必指出,免得误人子弟啊!
今天是第一战:带收放动画效果的菜单,效果如下图:(样式有点丑(-^-)) 
( 由于在写本文时,用的编辑器不同,暂时添加不了演示效果,这里有:最终完整代码和演示 ) 

JavaScript实战之带收放动画效果的导航菜单

动画效果:鼠标hover改变所有目标的背景和字体颜色,鼠标移动到‘首页导航',显示下面的分组菜单,分组菜单有子菜单,点击可缩放,带动画过度效果!而且,可以随便添加和删除导航菜单和子菜单,不影响效果! 

如何实现呢? 

第一步:用什么来实现菜单?HTML代码设计如下,遵循JS代码和HTML代码分离的原则!这里你看不到一句JS代码 

JavaScript实战之带收放动画效果的导航菜单

未应用样式之前是这个样子的:很古老吧!!! 

JavaScript实战之带收放动画效果的导航菜单

第二步:CSS样式。鼠标hover改变所有目标的背景和字体颜色,直接用CSS的transition和:hover,而其他的CSS样式布局就不全部列举了,大家自己动手吧,主要注意以下几点: 

#ul{
 ....
 z-index: 100;
 }
 #ul li{
 display: inline-block;
 position: relative;
 top: 0;
 left: -25px;
 width: 10%;
 min-width: 70px;
 height: 30px;
 text-align: center;
 line-height: 30px;
 border: 1px solid gray;
 border-radius:10px;
 background-color: aliceblue;
 cursor: pointer;
 -webkit-transition: all ease-in-out 0.3s;
 -moz-transition: all ease-in-out 0.3s;
 -ms-transition: all ease-in-out 0.3s;
 -o-transition: all ease-in-out 0.3s;
 transition: all ease-in-out 0.3s;
 }
 #ul li:hover{background-color: aquamarine;color: red;}
 ...
 .show-hide:hover{background-color: beige}
 .a-div{
 background-color: aquamarine;
 border-radius:10px;
 color: black;
 display: none;
 opacity: 0
 }
 .a{
 z-index: -1;
 display: block;
 ...
 }

第三步:这一步是重点。如果给每个菜单选项和分组都添加事件监听,个人觉得好麻烦,且代码量肯定多不少,有没有什么办法就在一个元素上加监听就能实现呢?

答案肯定是有的,利用事件的冒泡机制!在父元素ul标签上添加事件监听,而在监听函数里直接改变触发事件的元素样式就可以了,就这么简单!

代码如下:

var ul = document.getElementById('ul');
ul.addEventListener('mouseover',listener1,false);
ul.addEventListener('mouseout',listener2,false);
ul.addEventListener('click',listener3,false);
 

 因为IE8及以下版本没有addEventListener,如果要兼容,还得加attachEvent对应的代码。

第四:主角登场!实现listener1、listener2、listener3监听函数。

首先来最简单的listener1函数,代码如下:

function listener1(event){
 //event = event||window.event; //兼容IE8及以前版本
 var target = event.target||event.srcElement; //兼容IE8及以前版本
 if(target.tagName.toLowerCase() === 'li'){
 var div1 = target.getElementsByTagName('div')[0];
 div1.style.display = 'block';
 var i = 0;
 var id;
 (function foo(){
 if(i>=1){clearTimeout(id);id=null;return;}
 i+=0.2;
 div1.style.opacity = i;
 id = setTimeout(function(){clearTimeout(id);foo()},30);  


})();  

 }

 }

同样,一切为了IE8及更旧版本。

1.因为它的event没有target属性,只有相对应得srcElement属性

2.而这一句event = event||window.event;这里其实是可以省略的,只有当用属性来设置注册事件监听时,如ul.onmouseover = function(){},或<ul onmouseover='func'>,IE8及更旧版本只能通过window.event来取得当前的Event对象

好了,现在获得了当前触发事件的target,事情就简单很多了,通过他就可以改变它自己和它的亲戚!

下面是listener2函数,用在mouseout时触发,主要是操控target的子元素DIV,代码如下:

function listener2(event){
 //event = event||window.event;
 var target = event.target||event.srcElement;
 if(target.tagName.toLowerCase() === 'li'){
 var div1 = target.getElementsByTagName('div')[0];
 div1.onmouseover = function(){
 div1.style.display = 'block';
 div1.style.opacity = 1;
 };
 div1.onmouseout = function(){
 div1.style.display = 'none';
 div1.style.opacity = 0;
 };
 div1.style.display = 'none'; //这一组是为了实现当鼠标从上方出去时隐藏div1
 div1.style.opacity = 0;
 }
 }

好了,到这里,已经实现了大部分效果了,还有最后一步,那就是1号主角了:listener3函数,它主要负责鼠标点击时的缩放效果!

实现原理:  

1.函数外面定义一个bool变量当做开关,鼠标点一下开,再点一下关;

2.通过setTimeout来实现动画效果,动态的改变子菜单的height和opacity属性,还有display属性;

完整代码如下:

var bool = true;
 function listener3(event) {
 var event = event || window.event;
 var target = event.target || event.srcElement;
 if (target.className === 'show-hide') {
 var parent = target.parentElement;
 var adiv = parent.getElementsByClassName('a-div')[0];
 if (window.getComputedStyle(adiv,null).opacity>0.5){bool=false}else{bool=true}
 var height = 90,
 changeH,
 opacity,
 id;
 if (bool) {
 changeH = 0;
 opacity = 0;
 target.innerHTML = '财经 -';
 (function show() {
 if (changeH > height) {clearTimeout(id);return}
 changeH += 5;
 opacity += 0.06;
 //console.log('opacity:'+adiv.style.opacity+',height :'+adiv.style.height);
 adiv.style.height = changeH + 'px';
 adiv.style.opacity = opacity;
 adiv.style.display = 'block';
 id = setTimeout(function () {









 clearTimeout(id);
 show();
 }, 16.7);
 })();

 bool = false;
 } else {
 changeH = height;
 opacity = 1;
 target.innerHTML = '财经 +';
 (function hidden() {
 if (changeH < 0) {clearTimeout(id);adiv.style.display = 'none';return}
 changeH -= 10;
 opacity -= 0.11;
 //console.log('opacity:'+adiv.style.opacity+',height :'+adiv.style.height);
 adiv.style.height = changeH + 'px';
 adiv.style.opacity = opacity;
 id = setTimeout(function () {










 clearTimeout(id);
 hidden();
 }, 16.7);
 })();
 bool = true;
 }
 }
 }

注意几点:  

1.记得清除setTimeout的ID,然后退出,否则死循环,如if (changeH < 0) {clearTimeout(id);adiv.style.display = 'none';return}

2.setTimeout的延迟时间设置为16.7是因为符合屏幕的刷新率60FPS,看着舒服

3.调试过程中,设置changeH和opacity的递增递减值时,记得打印出来,方便调试:

console.log('opacity:'+adiv.style.opacity+',height :'+adiv.style.height);  

4.最后,整个菜单的实现中,最关键的是下面这一句,如果没有这一句,你无法完美实现所有功能,比如:你点开一组子菜单,然后移动到其它组点击的时候,情况将有很大不同;而window.getComputedStyle用这个的原因是,首次打开时,点任意组的第一下都没反应,因为直接通过event.target在点第一下时是取不到opacity值的。

if (window.getComputedStyle(adiv,null).opacity>0.5){bool=false}else{bool=true};

不过,IE9以下不支持getComputedStyle方法,IE的Element对象有currentStyle属性;

如果你对CSS的处理不是很熟悉,看看我的总结:用原生JS读写CSS样式的方法总结

如果你想多了解setTimeout()方法的应用,看看这个:你真的知道setTimeout是如何运行的吗

对于事件的处理机制,可以看看这个:DOM中的事件处理概览与原理的全面剖析

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript 字符串连接的性能问题(多浏览器)
Nov 18 Javascript
JS 拼图游戏 面向对象,注释完整。
Jun 18 Javascript
zeroclipboard复制到剪切板的flash
Aug 04 Javascript
JQuery UI的拖拽功能实现方法小结
Mar 14 Javascript
js history对象简单实现返回和前进
Oct 30 Javascript
JS复制到剪贴板示例代码
Oct 30 Javascript
javascript cookie用法基础教程(概念,设置,读取及删除)
Sep 20 Javascript
原生js封装的一些jquery方法(详解)
Sep 20 Javascript
jquery文字填写自动高度的实现方法
Nov 07 Javascript
实例介绍JavaScript中多种组合继承
Jan 20 Javascript
原生js实现随机点餐效果
Dec 10 Javascript
详解Typescript里的This的使用方法
Jan 08 Javascript
js 自带的sort() 方法全面了解
Aug 16 #Javascript
JavaScript实战之菜单特效
Aug 16 #Javascript
深入理解js generator数据类型
Aug 16 #Javascript
js 创建对象 经典模式全面了解
Aug 16 #Javascript
js 上传文件预览的简单实例
Aug 16 #Javascript
js removeChild 方法深入理解
Aug 16 #Javascript
关于javascript中限定时间内防止按钮重复点击的思路详解
Aug 16 #Javascript
You might like
php获取文件类型和文件信息的方法
2015/07/10 PHP
php设置页面超时时间解决方法
2015/09/22 PHP
Symfony2之session与cookie用法小结
2016/03/18 PHP
关于laravel模板中生成URL的几种模式总结
2019/10/18 PHP
经典的解除许多网站无法复制文字的绝招
2006/12/31 Javascript
javascript 的Document属性和方法集合
2010/01/25 Javascript
ajax不执行success回调而是执行了error回调
2012/12/10 Javascript
js返回上一页并刷新代码整理
2012/12/21 Javascript
JS测试显示屏分辨率以及屏幕尺寸的方法
2013/11/22 Javascript
使用原生js写的一个简单slider
2014/04/29 Javascript
node.js中的buffer.length方法使用说明
2014/12/14 Javascript
jQuery中each()方法用法实例
2014/12/27 Javascript
jQuery插件实现控制网页元素动态居中显示
2015/03/24 Javascript
JS时间特效最常用的三款
2015/08/19 Javascript
实例解析jQuery中proxy()函数的用法
2016/05/24 Javascript
用JS编写一个函数,返回数组中重复出现过的元素(实例)
2017/09/14 Javascript
使用node.js实现微信小程序实时聊天功能
2018/08/13 Javascript
mpvue全局引入sass文件的方法步骤
2019/03/06 Javascript
mpvue实现左侧导航与右侧内容的联动
2019/10/21 Javascript
ES5新增数组的实现方法
2020/05/12 Javascript
使用Nginx+uWsgi实现Python的Django框架站点动静分离
2016/03/21 Python
Python实现基于TCP UDP协议的IPv4 IPv6模式客户端和服务端功能示例
2018/03/22 Python
Python进阶之@property动态属性的实现
2019/04/01 Python
Pandas之Dropna滤除缺失数据的实现方法
2019/06/25 Python
python retrying模块的使用方法详解
2019/09/25 Python
python GUI库图形界面开发之PyQt5信号与槽多窗口数据传递详细使用方法与实例
2020/03/08 Python
定制别致的瑜伽垫:Sugarmat
2019/06/21 全球购物
有abstract方法的类一定要用abstract修饰吗
2016/03/14 面试题
给老师的道歉信
2014/01/11 职场文书
时尚休闲吧创业计划书
2014/01/25 职场文书
2014年小学元旦活动方案
2014/02/12 职场文书
《独坐敬亭山》教学反思
2014/04/08 职场文书
活动总结报告格式
2014/05/09 职场文书
总经理检讨书
2014/09/15 职场文书
模范教师事迹材料
2014/12/16 职场文书
借款民事起诉状范文
2015/05/19 职场文书