今天的目標和Day 23有點像
不過,今天我們要在滑鼠滑入時製作類似下拉式選單的效果
目標
當滑鼠滑入、滑出時其下方會出現對話框顯示資訊
首先先看一下html
<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>被忽略-->
</ul>
</nav>
再看css中的兩段程式碼
首先是是.dropdown
這個class
代表的是下拉式對話框的內容
這邊我們將在其父層加入trigger-enter
和trigger-enter-active
來新增display: block;
和opacity: 1;
來讓文字顯現
另外一段是dropdownBackground.open
來顯示對話框
.dropdown {
opacity: 0;
position: absolute;
...
display: none;
}
.trigger-enter .dropdown {
display: block;
}
.trigger-enter-active .dropdown {
opacity: 1;
}
.dropdownBackground {
width:100px;
height:100px;
position: absolute;
...
opacity:0;
}
.dropdownBackground.open {
opacity: 1;
}
根據以上要求
我們可以先寫初步的js
我們監聽trigger
的mouseenter
和mouseleave
事件
const triggers = document.querySelectorAll('.cool > li'); //選取要被滑入的element
const dropdownBackground = document.querySelector('.dropdownBackground');
const nav = document.querySelector('.top');
function dropdownEnter() {
//滑入時要顯示background、顯示內容
}
function dropdownLeave() {
//滑出時要隱藏background、隱藏內容
}
triggers.forEach(trigger => trigger.addEventListener('mouseenter', dropdownEnter));
triggers.forEach(trigger => trigger.addEventListener('mouseleave', dropdownLeave));
首先我們要先讓對話框background出現
滑入時在dropdownBackground
中加入.open
接著來處理內容
由於display
屬性無法有動畫效果
所以我們要仰賴opacity
在滑入時先將display
改成block
再利用setTimeout()
來等200ms
在實現漸入效果(opacity由0變成1)
滑出時就將上述的所有class移除
function dropdownEnter() {
dropdownBackground.classList.add('open');
this.classList.add('trigger-enter');
setTimeout(() => {
this.classList.add('trigger-enter-active');
}, 200);
}
function dropdownLeave() {
dropdownBackground.classList.remove('open');
this.classList.remove('trigger-enter', 'trigger-enter-active');
}
到這裡會發現內容已經能顯示了
但是dropdownBackground
尚未到正常的位置
因此我們可以使用.getBoundingClientRect()
得到下拉內容的element座標
由於我們只能拿到下拉內容到其父層的座標
所以我們還會需要其父層到body
的座標(也就是.top
的座標)coords
經過修正後才能讓含屬性position: absolute;
的dropdownBackground
能使用transform: translate();
到我們要的位置
function dropdownEnter() {
const dropdown = this.querySelector('.dropdown');
const dropdownCoords = dropdown.getBoundingClientRect();
const navCoords = nav.getBoundingClientRect();
const coords = {
width: dropdownCoords.width,
height: dropdownCoords.height,
top: dropdownCoords.top - navCoords.top,
left: dropdownCoords.left - navCoords.left
}
dropdownBackground.style.setProperty('width', `${coords.width}px`);
dropdownBackground.style.setProperty('height', `${coords.height}px`);
dropdownBackground.style.setProperty('transform', `translate(${coords.left}px, ${coords.top}px)`);
}