iT邦幫忙

0

JS30 Day 26 - Stripe Follow Along Nav學習筆記

今天的內容為導覽列顯示之觸發,當滑鼠移入導覽列,會顯示對應內容。

https://ithelp.ithome.com.tw/upload/images/20210130/201261827cegjzeiWR.png

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


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言