今天的内容为导览列显示之触发,当滑鼠移入导览列,会显示对应内容。
<body> <h2>Cool</h2> <nav class="top"> <div class="dropdownBackground"> <span class="arrow"></span> </div> <ul class="cool"> <li> <a href="#">About Me</a> <div class="dropdown dropdown1"> <div class="bio"> <img src="https://logo.clearbit.com/wesbos.com"> <p>Wes Bos sure does love web development. He teaches things like JavaScript, CSS and BBQ. Wait. BBQ isn't part of web development. It should be though!</p> </div> </div> </li> <li>...</li> <li>...</li> </ul> </nav> .trigger-enter .dropdown { display: block; } .trigger-enter-active .dropdown { opacity: 1; }
首先获取我们所需的元素。
// 获取所有的导览 const menus = document.querySelectorAll('.cool > li'); // 利用此dom作为显示各导览细项的基底 const dropdownBackground = document.querySelector('.dropdownBackground'); const nav = document.querySelector('.top');
将所有li也就是我们,各导览项增听事件。
menus.forEach(menu => { menu.addEventListener('mouseenter', enterHandler); menu.addEventListener('mouseleave', leaveHandler); });
在鼠标移入的函数当中,首先如果我们直接将样式利用classList.add加上去的话,视觉效果会很差不流畅,故我们利用setTimeout製造delay效果,当导览项目之内容背景显示出来后,内容才会跟着显示。
// 如果将样式同时加上去动画效果会不好 // this.classList.add('trigger-enter'); // this.classList.add('trigger-enter-active'); // 加入互动样式(dis block以获取座标) this.classList.add('trigger-enter'); // 在第二个样式加上delay setTimeout(() => { this.classList.contains('trigger-enter') && this.classList.add('trigger-enter-active'); }, 100);
而我们的导览列样式其实都是利用一个元素做为基底套下去的,故我们要获取对应导览列内容要显示的位置,此处利用getBoundingClientRect来获取元素相关之座标。
const dropdown = this.querySelector('.dropdown'); // 获取其元素之座标DOMRect {x: 0, y: 0, width: 0, height: 0, top: 0, …} 一开始都获得0是因为他初始样式设置display:none const rect = dropdown.getBoundingClientRect();
但利用getBoundingClientRect获取之座标皆是最外层获取,故我们要扣除掉在nav上方多出来的距离。
// 获取多出来的距离 const [navTop, navLeft] = [nav.offsetTop, nav.offsetLeft]; console.log(rect); const menuRect = { width: rect.width, height: rect.height, top: rect.top, left: rect.left } dropdownBackground.classList.add('open'); dropdownBackground.style.width = rect.width + "px"; dropdownBackground.style.height = rect.height + "px"; // 因为座标top是由整个画面开始,所以我们要扣掉多出来的(nav至顶端的距离) dropdownBackground.style.top = (rect.top - navTop) + "px"; dropdownBackground.style.left = (rect.left - navLeft) + "px"; }
鼠标离开时,样式也跟着移除。
function leaveHandler(e) { e.stopPropagation(); this.classList.remove('trigger-enter'); // 在第二个样式加上delay this.classList.remove('trigger-enter-active'); dropdownBackground.classList.remove('open'); }