JS30 Day 26 筆記


Posted by GL on 2023-05-23

目標

做一個隨著滑鼠移動展開下拉選單的導覽列

Demo

step 1 : 取得 HTML 頁面元素,并且建立監聽事件

// 取得導覽列 nav bar 中的每一個選項
const triggers = document.querySelectorAll('.cool > li');
// 取得下拉選單的白色背景
const background  = document.querySelector('.dropdownBackground');
// 取得整個導覽列 nav bar
const nav  = document.querySelector('.top');

// 滑鼠移入事件
function handleEnter() {
  console.log('mouse in')
}

// 滑鼠移出事件
function handleLeave() {
  console.log('mouse out')
}

// 在導覽列每個選項監聽 mouseenter、mouseLeave 事件
triggers.forEach(trigger => trigger.addEventListener('mouseenter', handleEnter));
triggers.forEach(trigger => trigger.addEventListener('mouseleave', handleLeave));

step 2 : handleEnter function

function handleEnter() {
  console.log('mouse in')
  // 滑鼠指到的選項 li,增加 trigger-enter 的 css 樣式
  this.classList.add('trigger-enter');
  // 爲避免 trigger-enter-active 的樣式先於 trigger-enter 先出現
  // 當滑鼠移入 li 元素的選項時,先檢查是否有 trigger-enter className
  // 若有,才會在 150 ms 後新增 trigger-enter-active 這個 class name
  setTimeout(() => this.classList.contains('trigger-enter') && this.classList.add('trigger-enter-active'), 150);

  // 在白色背景增加 open 這個 class,讓 opacity 顯示為 1
  background.classList.add('open');

  // 取得滑鼠滑入的 li 元素選項下方的 dropdown
  const dropdown = this.querySelector('.dropdown');
  // 取得這個 dropdown 的大小以及位置等資訊
  const dropdownCoords = dropdown.getBoundingClientRect();
  // 取得 nav 的大小以及位置等資訊
  const navCoords = nav.getBoundingClientRect();

  // coords 物件儲存白色背景根據下拉選單的大小與位置,做相應的位移
  const coords =
    {
      height: dropdownCoords.height,
      width: dropdownCoords.width,
      // 出現上方因 nav 的出現而增加的唯一,因此減去 nav 的位置
      top: dropdownCoords.top - navCoords.top,
      left: dropdownCoords.left - navCoords.left
    };

  // CSS style 設定白色背景的大小和位置
  background.style.setProperty('width', `${coords.width}px`);
  background.style.setProperty('height', `${coords.height}px`);
  background.style.setProperty('transform', `translate(${coords.left}px, ${coords.top}px)`);
}

step 3 : handleLeave function

function handleLeave(){
  console.log('mouse out')
  // 移除在 mouseenter 被加上的 class 樣式
  this.classList.remove('trigger-enter','trigger-enter-active')
  background.classList.remove('open')
}

補充

  1. 讓元素從畫面消失的方法:
    display:none : 呈現時看不出有該元素的存在
    visibility:hidden: 看不出有該元素的存在,但保留元素原本的位置與大小
  2. opacity 表示元素的透明度,數值為 0 ~ 1,數字越小越透明。
  3. 這次的範例中利用 js 控制 css 的 class 樣式的開關,進而控制元素是否顯示
.dropdown {
  /* 下拉選單原本的 opacity:0,display: none; */
  opacity: 0;
  position: absolute;
  overflow: hidden;
  padding: 20px;
  top: -20px;
  border-radius: 2px;
  transition: all 0.5s;
  transform: translateY(100px);
  will-change: opacity;
  display: none;
}

/* 加了 trigger-enter 之後 display: block,
 * getBoundingClientRect() 可以計算變成 block 後大小與位置 */
.trigger-enter .dropdown {
  display: block;
}

/* 加了 trigger-enter-active class 之後 opacity 為 1 */
.trigger-enter-active .dropdown {
  opacity: 1;
}

.dropdownBackground {
  width: 100px;
  height: 100px;
  position: absolute;
  background: #fff;
  border-radius: 4px;
  box-shadow: 0 50px 100px rgba(50, 50, 93, .1), 0 15px 35px rgba(50, 50, 93, .15), 0 5px 15px rgba(0, 0, 0, .1);
  transition: all 0.3s, opacity 0.1s, transform 0.2s;
  transform-origin: 50% 0;
  display: flex;
  justify-content: center;
  /* 下拉選單白色背景原本的 opacity 為 0 */
  opacity: 0;
}

/* 加了 open class 之後 opacity 為 1 */
.dropdownBackground.open {
  opacity: 1;
}

參考資料:


#JS 30







Related Posts

深入 Session 與 Cookie:Express、PHP 與 Rails 的實作

深入 Session 與 Cookie:Express、PHP 與 Rails 的實作

如何使用 K8S 自動化定期 CronJob 抓網路公開資料

如何使用 K8S 自動化定期 CronJob 抓網路公開資料

資料格式的選擇

資料格式的選擇


Comments