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 相关文章推荐
jquery图片放大功能简单实现
Aug 01 Javascript
js判断选择的时间是否大于今天的代码
Aug 20 Javascript
javascript实现youku的视频代码自适应宽度
May 25 Javascript
JavaScript获取两个数组交集的方法
Jun 09 Javascript
JavaScript判断对象是否为数组
Dec 22 Javascript
详解Node.js中的事件机制
Sep 22 Javascript
javascript实现获取指定精度的上传文件的大小简单实例
Oct 25 Javascript
Bootstrap 3 进度条的实现
Feb 22 Javascript
详解vue + vuex + directives实现权限按钮的思路
Oct 24 Javascript
vue组件间通信子与父详解(二)
Nov 07 Javascript
简单两步使用node发送qq邮件的方法
Mar 01 Javascript
Electron实现应用打包、自动升级过程解析
Jul 07 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
Windows下的PHP5.0详解
2006/11/18 PHP
php图片缩放实现方法
2014/02/20 PHP
thinkPHP5.0框架命名空间详解
2017/03/18 PHP
PHP删除二维数组中相同元素及数组重复值的方法示例
2017/05/05 PHP
Jquery ThickBox插件使用心得(不建议使用)
2010/09/08 Javascript
js将控件隐藏的方法及display属性介绍
2013/07/04 Javascript
js 鼠标移动显示图片的简单实例
2013/12/25 Javascript
node.js中的path.isAbsolute方法使用说明
2014/12/08 Javascript
JavaScript 中对象的深拷贝
2016/12/04 Javascript
js实现键盘自动打字效果
2016/12/23 Javascript
原生JS实现简单放大镜效果
2017/02/08 Javascript
原生JS+Canvas实现五子棋游戏
2020/05/28 Javascript
jQuery实现点击图标div循环放大缩小功能
2018/09/30 jQuery
js数组去重的方法总结
2019/01/18 Javascript
VUE项目axios请求头更改Content-Type操作
2020/07/24 Javascript
JavaScript 空间坐标的使用
2020/08/19 Javascript
js实现鼠标切换图片(无定时器)
2021/01/27 Javascript
[08:42]DOTA2每周TOP10 精彩击杀集锦vol.2
2014/06/25 DOTA
在Python中操作文件之seek()方法的使用教程
2015/05/24 Python
python3音乐播放器简单实现代码
2020/04/20 Python
基于Python实现拆分和合并GIF动态图
2019/10/22 Python
Python Numpy数组扩展repeat和tile使用实例解析
2019/12/09 Python
paramiko使用tail实时获取服务器的日志输出详解
2020/12/06 Python
python实现计算图形面积
2021/02/22 Python
基于Pytorch版yolov5的滑块验证码破解思路详解
2021/02/25 Python
使用HTML5原生对话框元素并轻松创建模态框组件
2019/03/06 HTML / CSS
日本最佳原创设计品牌:Felissimo(芬理希梦)
2019/03/19 全球购物
北欧最好的童装网上商店:Babyshop
2019/09/15 全球购物
Deux par Deux官方网站:设计师童装
2020/01/03 全球购物
sealed修饰符是干什么的
2012/10/23 面试题
自我鉴定模板
2013/10/29 职场文书
推荐信怎么写
2014/05/09 职场文书
个人担保书范文
2014/05/20 职场文书
食品质量与安全专业毕业生求职信
2014/08/11 职场文书
工作时间擅自离岗检讨书
2014/10/24 职场文书
golang通过递归遍历生成树状结构的操作
2021/04/28 Golang