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下判断IE与FF的比较简单的方式
Oct 17 Javascript
zepto.js中tap事件阻止冒泡的实现方法
Feb 12 Javascript
Bootstrap树形组件jqTree的简单封装
Jan 25 Javascript
基于jquery实现下拉框美化特效
Feb 02 Javascript
微信小程序 小程序制作及动画(animation样式)详解
Jan 06 Javascript
js控制按钮,防止频繁点击响应的实例
Feb 15 Javascript
ionic2屏幕适配实现适配手机、平板等设备的示例代码
Aug 11 Javascript
详细介绍RxJS在Angular中的应用
Sep 23 Javascript
Angular4学习之Angular CLI的安装与使用教程
Jan 04 Javascript
详解vue 数据传递的方法
Apr 19 Javascript
Vue+webpack项目配置便于维护的目录结构教程详解
Oct 14 Javascript
js页面加载后执行的几种方式小结
Jan 30 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安全性需要注意的几点事项
2014/07/17 PHP
PHP单例模式详细介绍
2015/07/01 PHP
php strftime函数获取日期时间(switch用法)
2018/05/16 PHP
jquery 问答知识整理
2010/02/11 Javascript
高性能WEB开发 flush让页面分块,逐步呈现 flush让页面分块,逐步呈现
2010/06/19 Javascript
深入理解JavaScript系列(12) 变量对象(Variable Object)
2012/01/16 Javascript
jQuery中:last-child选择器用法实例
2014/12/31 Javascript
jQuery中eq()方法用法实例
2015/01/05 Javascript
jQuery实现HTML表格单元格的合并功能
2016/04/06 Javascript
如何使用jquery修改css中带有!important的样式属性
2016/04/28 Javascript
深入理解jQuery 事件处理
2016/06/14 Javascript
详谈ES6中的迭代器(Iterator)和生成器(Generator)
2017/07/31 Javascript
nodejs实现一个word文档解析器思路详解
2018/08/14 NodeJs
Vue的编码技巧与规范使用详解
2019/08/28 Javascript
微信小程序实现导航栏和内容上下联动功能代码
2020/06/29 Javascript
使用Protocol Buffers的C语言拓展提速Python程序的示例
2015/04/16 Python
使用Python判断质数(素数)的简单方法讲解
2016/05/05 Python
pycharm使用matplotlib.pyplot不显示图形的解决方法
2018/10/28 Python
window7下的python2.7版本和python3.5版本的opencv-python安装过程
2019/10/24 Python
python 统计文件中的字符串数目示例
2019/12/24 Python
Python的对象传递与Copy函数使用详解
2019/12/26 Python
使用keras和tensorflow保存为可部署的pb格式
2020/05/25 Python
Python Selenium实现无可视化界面过程解析
2020/08/25 Python
python爬取豆瓣电影排行榜(requests)的示例代码
2021/02/18 Python
python matplotlib工具栏源码探析二之添加、删除内置工具项的案例
2021/02/25 Python
全球最大的在线橄榄球商店:Lovell Rugby
2018/05/20 全球购物
全球异乡人的跨境社交电商平台:Kouhigh口嗨网
2020/07/24 全球购物
我能否用void** 指针作为参数, 使函数按引用接受一般指针
2013/02/16 面试题
生日派对邀请函
2014/01/13 职场文书
端午节粽子促销活动方案
2014/02/02 职场文书
公益广告语集锦
2014/03/13 职场文书
公司保密承诺书
2014/03/27 职场文书
小学庆六一主持词
2015/06/30 职场文书
OpenCV-Python实现轮廓拟合
2021/06/08 Python
springboot临时文件存储目录配置方式
2021/07/01 Java/Android
Win11绿屏怎么办?Win11绿屏死机的解决方法
2021/11/21 数码科技