在今天的課題當中,我們要將第22天的課題 Follow Along Link HighLighter 聚光燈的效果,做進一步的利用。
當我們把滑鼠移到列表標題上時,下方的列表就會浮現,並且將我們的聚光燈移到列表上。[1]
實作連結
根據第22天的課題內容,我們已經學會聚光燈元素的原理及方法。而要讓內容呈現的話,就需要來認識 display:none
以及 opacity
這兩個 CSS 屬性。
display:none
CSS 屬性,能將元素從畫面中移除,讓頁面呈現時看不出有該元素的存在。另一種使元素消失的方法為 visibility:hidden
,使用這種 CSS 屬性,雖然也能讓元素從畫面上消失,但是他會保留原本元素的位置與大小,所以在頁面中會看到一塊空白。[2]
opacity
CSS 屬性,代表的是元素的透明度,其值為0~1。0代表透明程度為0%,因此元素為完全不透明狀態。1則是代表100%,因此元素為完全透明。[3]
了解以上兩個 CSS 屬性的特性之後,我們就可以理解為何需要額外加上 display:none
屬性,如果我們只更動了 opacity:0
這個屬性,則會發生看不到東西卻點得到的靈異事件:
將以上兩種屬性結合起來,並透過觸發事件來更動元素 CSS 屬性,我們就能完成今天的課題。
首先我們將需要的元素選取起來,並加上監聽事件 onmouseenter
與 <mouseleave>
,讓滑鼠移入與移出指定元素的時候觸發事件:
const triggers = document.querySelectorAll('.cool > li');
const background = document.querySelector('.dropdownBackground');
const nav = document.querySelector('.top');
triggers.forEach(trigger => trigger.addEventListener('mouseenter', handleEnter));
triggers.forEach(trigger => trigger.addEventListener('mouseleave', handleLeave));
這邊加上監聽事件的元素選為 <li>
容器元素,這是因為如果我們選擇裡頭的子元素為事件目標,當我們滑鼠移到子元素之間的空隙,我們的表單就因為無觸發 onmouseenter
事件而消失。
在我們的觸發函式之中,我們要完成 CSS 屬性的更換,因此可以透過將元素新增、移除 class
來做出此效果,我們希望元素先出現在頁面上,延遲之後再顯示內容,因此我們分別加上兩個 class
,第一個先將 display:none
屬性更改掉,後面的則是利用 setTimeout()
方法,延遲一段時間後更改內容的透明度,而當滑鼠移開時,則是同時移除:
function handleEnter(event) {
const showItem = event.target;
showItem.classList.add('trigger-enter');
setTimeout(function () {
if (showItem.classList.contains('trigger-enter')) {
showItem.classList.add('trigger-enter-active');
}
}, 150);
};
function handleLeave(event) {
const missItem = event.target;
missItem.classList.remove('trigger-enter', 'trigger-enter-active');
};
.trigger-enter .dropdown {
display: block;
}
.trigger-enter-active .dropdown {
opacity: 1;
}
再來要加上聚光燈的效果,我們一樣也是透過 element.getBoundingClientRect()
方法,取得元素的大小以及位置。但是我們要特別注意到這次作為聚光燈背景的元素 <div class="dropdownBackground">
是被放在 <nav>
容器元素之下,且 position:absolute
屬性,是相對其父元素做定位,因此當容器上方有其他高度存在的元素,將造成聚光燈打歪,因此我們需要額外加上<nav>
容器的位置幫助判斷,完整函式內容程式碼如下:
function handleEnter(event) {
const showItem = event.target;
showItem.classList.add('trigger-enter');
setTimeout(function () {
if (showItem.classList.contains('trigger-enter')) {
showItem.classList.add('trigger-enter-active');
}
}, 150);
background.classList.add('open');
//取得觸發事件父元素中的 '.dropdown' 子元素
const dropdown = this.querySelector('.dropdown');
//取得該子元素的大小及位置資料
const dropdownCoords = dropdown.getBoundingClientRect();
//取得 <nav> 元素的大小及位置資料
const navCoords = nav.getBoundingClientRect();
//設定聚光燈背景元素的大小及位置
background.style.width = `${dropdownCoords.width}px`;
background.style.height = `${dropdownCoords.height}px`;
background.style.top = `${dropdownCoords.top - navCoords.top}px` ;
background.style.left = `${dropdownCoords.left- navCoords.left}px`;
};
function handleLeave(event) {
const missItem = event.target;
missItem.classList.remove('trigger-enter', 'trigger-enter-active');
background.classList.remove('open');
};
.dropdownBackground.open {
opacity: 1;
}
今天學到新的 CSS 屬性如下:
display:none
visibility:hidden
opacity
今天我們將第22天學到的方法,結合新的 CSS 屬性,做出隱形的表單。其實我們可以發現,要做出頁面特效的話,透過簡單的監聽事件函式與元素 CSS 屬性更換,就可以創造出許多酷炫的頁面特效。
到目前為止,JS30已經進入倒數5天,相信大家都跟我一樣對網頁特效的恐懼感有逐漸消失,深信在完成JS30之後,我們都能具備將腦中的特效想法,實作出來的能力!