这次通过中小DEMO,更加深入地了解了
1、使用块模式-立即执行匿名函数,有效地避免了javascript中没有私有作用域而造成的代码污染全局或被覆盖;(function(){})();
2、Javascript事件的冒泡传播机制,使在外部的div上能监听到里面按钮的事件响应
3、修改了事件函数内的this指向回创建对象的两种方法
4、CSS中animation动画属性和keyframes关键帧的transform动画效果,完成了侧边栏内容展示效果的动画效果。
等等
一、使用HTML+CSS实现侧边栏页面布局
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>sidebar demo</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <link rel="stylesheet" href="sidebar.css"> </head> <body> <div id="sidebar"> <ul> <li id="me"class="item"> <span class="glyphicon glyphicon-user"></span> <div>我</div> </li> <li id="prof"class="item"> <span class="glyphicon glyphicon-usd"></span> <div>资产</div> </li> <li id="asset"class="item"> <span class="glyphicon glyphicon-apple"></span> <div>品牌</div> </li> <li id="broadcast"class="item"> <span class="glyphicon glyphicon-facetime-video"></span> <div>直播</div> </li> <li id="foot"class="item"> <span class="glyphicon glyphicon-eye-open"></span> <div>看过</div> </li> <li id="calendar"class="item"> <span class="glyphicon glyphicon-star-empty"></span> <div>日历</div> </li> </ul> <div id="closeBar"> <span class="glyphicon glyphicon-remove"></span> </div> </div> <div class="nav-content" id="me-content"> <div> <div class="nav-con-close"> <i class="glyphicon glyphicon-menu-left "></i> </div> <div>我</div> </div> </div> <div class="nav-content" id="prof-content"> <div> <div class="nav-con-close"> <i class="glyphicon glyphicon-menu-left "></i> </div> <div>资产</div> </div> </div> <div class="nav-content" id="asset-content"> <div> <div class="nav-con-close"> <i class="glyphicon glyphicon-menu-left "></i> </div> <div>品牌</div> </div> </div> <div class="nav-content" id="broadcast-content"> <div> <div class="nav-con-close"> <i class="glyphicon glyphicon-menu-left "></i> </div> <div>直播</div> </div> </div> <div class="nav-content" id="foot-content"> <div> <div class="nav-con-close"> <i class="glyphicon glyphicon-menu-left "></i> </div> <div>看过</div> </div> </div> <div class="nav-content" id="calendar-content"> <div> <div class="nav-con-close"> <i class="glyphicon glyphicon-menu-left "></i> </div> <div>日历</div> </div> </div> <script type="text/javascript" src="js/sidebar.js"></script> </body> </html>
-
position:fixed;属性
-
dom结构对代码的实现
closebar作为sidebar element的子元素,在实现动画效果时利用querySelectorAll()方式就可简单实现
实现菜单内容项nav-content时,使它与sidebar平级,都是body的子元素,使用opacity来控制菜单内容项是否显示
ul{ list-style: none; padding-left: 0; } #sidebar { width: 35px; background-color: #e1e1e1; padding-top: 200px; position: fixed;/*可以使sidebar脱离文档流,使min-height:100%成为一个全屏高度*/ min-height: 100%; z-index: 100; } .item { font-size: 12px; font-family: 'Andale Mono' text-align: center; margin-top: 5px; cursor: pointer; } #closeBar{ position: absolute; bottom: 30px; width: 35px; text-align: center; cursor: pointer; } .nav-content{ width: 200px; position: fixed; min-height: 100%; background: #e1e1e1; border: 1px solid black; z-index: 99; opacity: 0; } .nav-con-close{ position: absolute; top: 5px; right: 5px; cursor: pointer; /* z-index: 99;*/ }
二、使用Javascript的构造函数创建对象
- 使用面向对象的方式:
根据sidebar对象state属性是opened还是closed,来调用原型链中的相应方法,使代码更加清晰
Sidebar.prototype.triggerSwitch = function(){ if(this.state === 'opened'){ this.close(); }else{ this.open(); } };
2.在添加事件响应函数的时候,把关闭、打开事件添加在sidebar本身。
(function(){ var Sidebar = function(eId,closeBarId){ this.state = 'opened'; }; Sidebar.prototype.close = function(){}; Sidebar.prototype.open = function(){}; )();
/*使用块模式--立即执行的匿名函数*/ (function(){ //所有声明的变量在构造函数内部,不会向windows添加任何属性 /* 构造函数的基本规范: 1、构造函数的第一个字母是大写的,与其他函数区分开来 2、调用构造函数的时候需要用new,不然会创建全局变量 */ var Menubar = function(){ this.el = document.querySelector('#sidebar ul'); //菜单项的DOM元素通过css的querySelctor查找得到 this.state = 'allClosed';//初始状态时,allClosed,当打开某一个时,则为hasOpened this.el.addEventListener('click',function(e){ //7.1阻止冒泡事件向上传播,这样点击菜单项,只响应菜单项事件,无关sidebar e.stopPropagation(); }); var self = this; var currentOpendMenuContent = null; //7.2点击菜单项添加监听事件 this.menuList = document.querySelectorAll('#sidebar ul > li'); for( var i=0; i<this.menuList.length;i++){ this.menuList[i].addEventListener('click',function(e){ //找到相应的菜单项的内容区域 var menuContentEl = document.getElementById(e.currentTarget.id + '-content' ); /* 7.2-1:没有打开菜单项,打开响应的菜单项 7.2-2:有打开的菜单项,关闭该菜单项再打开响应的菜单项 */ if(self.state === 'allClosed'){ console.log( '打开' + menuContentEl.id); /*9.1菜单项打开的动画效果*/ //先设置菜单栏的高和左边的位置 menuContentEl.style.top = '0px'; menuContentEl.style.left = '-85px'; menuContentEl.classList.add('menuContent-move-right'); self.state = 'hasOpened'; self.currentOpendMenuContent = menuContentEl; }else{ console.log('关闭' + self.currentOpendMenuContent.id); /*9.2菜单栏关闭的动画效果*/ self.currentOpendMenuContent.className = 'nav-content'; self.currentOpendMenuContent.style.top = '0'; self.currentOpendMenuContent.style.left = '35px'; self.currentOpendMenuContent.classList.add('menuContent-move-left') console.log( '打开' + menuContentEl.id); menuContentEl.className = "nav-content" menuContentEl.style.top = '250px'; menuContentEl.style.left = '35px'; menuContentEl.classList.add('menuContent-move-up'); self.state = 'hasOpened'; self.currentOpendMenuContent = menuContentEl; } }); } /*10、关闭按钮的样式*/ this.menuContentList = document.querySelectorAll('.nav-content >div.nav-con-close'); for(i=0;i<this.menuContentList.length;i++){ this.menuContentList[i].addEventListener('click', function(e){ //要关闭菜单内容项,所以要先得到菜单内容项 var menuContent = e.currentTarget.parentNode; menuContent.className = "nav-content"; menuContent.style.top = '0'; menuContent.style.left = '35px'; menuContent.classList.add('menuContent-move-left'); that.state = 'allClosed'; }); } }; /*1、使用构造函数创建sidebar对象 , 实例化该对象,向内提供属性eId、closeId*/ var Sidebar = function(eId,closeBarId){ /*2、定义对象的状态和属性和方法*/ this.state = 'opened'; /*4、继续完成构造函数 4.1、完成对象的初始化,获取所需要的DOM元素 4.2、在构造函数的关闭按钮中增加事件响应函数 {借助Javascript的事件的冒泡传播机制:使用向上冒泡的机制来传播,在'sidebar的div上能监听closebar按钮的事件响应'} */ this.el = document.getElementById(eId || 'sidebar'); //在参数中,需要传入默认的id以防不提供参数 this.closeBarEl = document.getElementById(closeBarId || 'closeBar'); /*4.3、在el元素上面调用事件函数*/ var self = this; /* 修改事件函数内的this指向回Sidebar对象有两种方法: 1、修改函数的上下文(比较复杂) 2、javascript的特性--闭包 this指向构造函数返回的对象,则指向下方 new sidebar返回的对象, 闭包原理,再在事件响应函数中调用该变量 */ /*7、在sidebar构造函数中,需要将Menubar函数作为一个属性传进*/ this.menubar = new Menubar(); this.el.addEventListener("click",function(event){ if(event.target !== self.el){ self.triggerSwitch(); //代表打开和关闭的统一函数名称 } }); }; /*3、声明sidebar的两个行为 对象的行为添加在构造函数的原型链上*/ Sidebar.prototype.close = function(){ console.log('关闭sidebar'); /*8、增加sidebar和关闭按钮的动画效果*/ this.el.className = 'sidebar-move-left'; this.closeBarEl.className = 'closeBar-move-right'; this.state = 'closed'; }; Sidebar.prototype.open = function(){ console.log('打开sidebar'); /* 9、增加sidebar打开和关闭按钮向左移动的动画效果*/ //9.1需要先将sidebar的位置定位到上次关闭的位置 this.el.style.left ='-120px'; this.el.className = 'sidebar-move-right'; this.closeBarEl.style.left = '160px'; this.closeBarEl.className = 'closeBar-move-left'; this.state = 'opened'; }; /*5、增加triggerSwich()函数*/ Sidebar.prototype.triggerSwitch = function(){ if(this.state === 'opened'){ this.close(); }else{ this.open(); } }; /*6、验证构造函数的成果 6.1在close函数中console.log输出值来验证 6.2增加test单元测试,单元测试一直伴随代码存在*/ var sidebar = new Sidebar(); })();
三、侧边栏信息展示效果的动画效果的添加
1.使用JavaScript的setInterval,但是这种方法实现的动画不够流畅,实现效果较少,也比较复杂
2.多运动CSS3的动画效果:animations
scale实现closebar大小的缩放
rotate实现关闭按钮的旋转
translateX实现水平方向位移
translateY实现垂直方向位移
/* sidebar向左移动的动画属性 animation样式 */ .sidebar-move-left { -webkit-animation-name: sml; -moz-animation-name: sml; -o-animation-name: sml; animation-name: sml; -webkit-animation-duration: 1s; -moz-animation-duration: 1s; -o-animation-duration: 1s; animation-duration: 1s; -webkit-animation-iteration-count: 1; -moz-animation-iteration-count: 1; -o-animation-iteration-count: 1; animation-iteration-count: 1; -webkit-animation-fill-mode: forwards; -moz-animation-fill-mode: forwards; -o-animation-fill-mode: forwards; animation-fill-mode: forwards; } /* 关键帧的动画效果 */ @-webkit-keyframes sml{ from{ } to{ -webkit-transform: translateX(-120px); } } @keyframes sml{ from{ } to{ -webkit-transform: translateX(-120px); transform: translateX(-120px); } } /* 关闭按钮向右移动的动画属性 */ .closeBar-move-right{ -webkit-animation-name: sl; -moz-animation-name: sl; -o-animation-name: sl; animation-name: sl; -webkit-animation-duration: 1s; -moz-animation-duration: 1s; -o-animation-duration: 1s; animation-duration: 1s; -webkit-animation-iteration-count: 1; -moz-animation-iteration-count: 1; -o-animation-iteration-count: 1; animation-iteration-count: 1; -webkit-animation-fill-mode: forwards; -moz-animation-fill-mode: forwards; -o-animation-fill-mode: forwards; animation-fill-mode: forwards; } @-webkit-keyframes sl{ from{ } to{ -webkit-transform: translateX(160px) rotate(405deg) scale(1.5); } } @keyframes sl{ from{ } to{ -webkit-transform: translateX(160px) rotate(405deg) scale(1.5); transform: translateX(160px) rotate(405deg) scale(1.5); } } /* sidebar向右打开的动画效果 */ .sidebar-move-right{ -webkit-animation-name: smr; -moz-animation-name: smr; -o-animation-name: smr; animation-name: smr; -webkit-animation-duration: 1s; -moz-animation-duration: 1s; -o-animation-duration: 1s; animation-duration: 1s; -webkit-animation-iteration-count: 1; -moz-animation-iteration-count: 1; -ms-animation-iteration-count: 1; -o-animation-iteration-count: 1; animation-iteration-count: 1; -webkit-animation-fill-mode: forwards; -moz-animation-fill-mode: forwards; -ms-animation-fill-mode: forwards; -o-animation-fill-mode: forwards; animation-fill-mode: forwards; } @keyframes smr{ from{ } to{ transform: translateX(120px); } } .closeBar-move-left { -webkit-animation-name: sr; -moz-animation-name: sr; -o-animation-name: sr; animation-name: sr; -webkit-animation-duration: 1s; -moz-animation-duration: 1s; -o-animation-duration: 1s; animation-duration: 1s; -webkit-animation-iteration-count: 1; -moz-animation-iteration-count: 1; -o-animation-iteration-count: 1; animation-iteration-count: 1; -webkit-animation-fill-mode: forwards; -moz-animation-fill-mode: forwards; -o-animation-fill-mode: forwards; animation-fill-mode: forwards; } @-webkit-keyframes sr{ from{ transform : scale(1.5); -webkit-transform : scale(1.5); } to{ transform: translateX(-160px) scale(1) rotate(-405deg); -webkit-transform: translateX(-160px) scale(1) rotate(-405deg); } } @keyframes sr{ from{ -webkit-transform : scale(1.5); transform : scale(1.5); } to{ -webkit-transform: translateX(-160px) scale(1) rotate(-405deg); transform: translateX(-160px) scale(1) rotate(-405deg); } } .menuContent-move-right { -webkit-animation-name: mmr; -moz-animation-name: mmr; -o-animation-name: mmr; animation-name: mmr; -webkit-animation-duration: .5s; -moz-animation-duration: .5s; -o-animation-duration: .5s; animation-duration: .5s; -webkit-animation-iteration-count: 1; -moz-animation-iteration-count: 1; -o-animation-iteration-count: 1; animation-iteration-count: 1; -webkit-animation-fill-mode: forwards; -moz-animation-fill-mode: forwards; -o-animation-fill-mode: forwards; animation-fill-mode: forwards; } @keyframes mmr{ from{ opacity: 0; } to{ opacity: 1; transform: translateX(120px); } } .menuContent-move-left { -webkit-animation-name: mml; -moz-animation-name: mml; -o-animation-name: mml; animation-name: mml; -webkit-animation-duration: .5s; -moz-animation-duration: .5s; -o-animation-duration: .5s; animation-duration: .5s; -webkit-animation-iteration-count: 1; -moz-animation-iteration-count: 1; -o-animation-iteration-count: 1; animation-iteration-count: 1; -webkit-animation-fill-mode: forwards; -moz-animation-fill-mode: forwards; -o-animation-fill-mode: forwards; animation-fill-mode: forwards; } @-webkit-keyframes mml{ from{ opacity: 1; } to{ opacity: 0; -webkit-transform: translateX(-120px); transform: translateX(-120px); } } @keyframes mml{ from{ opacity: 1; } to{ opacity: 0; transform: translateX(-120px); } } .menuContent-move-up { -webkit-animation-name: mmu; -moz-animation-name: mmu; -o-animation-name: mmu; animation-name: mmu; -webkit-animation-duration: .5s; -moz-animation-duration: .5s; -o-animation-duration: .5s; animation-duration: .5s; -webkit-animation-iteration-count: 1; -moz-animation-iteration-count: 1; -o-animation-iteration-count: 1; animation-iteration-count: 1; -webkit-animation-fill-mode: forwards; -moz-animation-fill-mode: forwards; -o-animation-fill-mode: forwards; animation-fill-mode: forwards; } @-webkit-keyframes mmu{ from{ opacity: 0; } to{ opacity: 1; -webkit-transform: translateY(-250px); transform: translateY(-250px); } } @keyframes mmu{ from{ opacity: 0; } to{ opacity: 1; transform: translateY(-250px); } }