iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 27
0
Modern Web

寫JS30天系列 第 27

JS30 - 27 - Stripe Follow Along Nav

  • 分享至 

  • xImage
  •  

今天的目標和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-entertrigger-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
我們監聽triggermouseentermouseleave事件

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)`);
}

Demo
完整程式碼


上一篇
JS30 - 26 - Event Capture, Propagation, Bubbling and Once
下一篇
JS30 - 28 - Click and Drag
系列文
寫JS30天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言