iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 26
0

Day26 Stripe Follow Along Dropdown

第26天的實作為第22天的延伸,在第22天是當滑鼠移到特定元素會給該元素有highlight的效果,而第26天就做出跟stripenav元素一樣的效果。

如何要做出這特效,原理為取得目標顯示元素的寬、高度和在網頁中的相對位置,並把的寬、高度和位置加到div元素中,讓div元素移動到目標目標的位置,並加入CSS的特效。

首先nav包含要有滑鼠指定元素li,在li元素裡有類別為dropdown的元素。

<nav class="top">
    <ul class="cool">
      <li>
        <a href="#">About Me</a>
        <div class="dropdown dropdown1">
            。
        </div>
      </li>
      <li>
        <a href="#">Courses</a>
        <ul class="dropdown courses">
            。
        </ul>
      </li>
      <li>
        <a href="#">Other Links</a>
        <ul class="dropdown dropdown3">
            。
        </ul>
      </li>
    </ul>
</nav>

在類別dropdown中的每一個元素為不顯示display: none

.dropdown {
    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;
  }

接下來在nav元素中的每一個li元素建立兩個事件,第一個為滑鼠移出事件以及第二個是滑鼠移入事件。

triggers.forEach(trigger => trigger.addEventListener('mouseenter', handleEnter))
triggers.forEach(trigger => trigger.addEventListener('mouseleave', handelLeave))

滑鼠移出事件,為目標元素移除CSS類別即可。

this.classList.remove('trigger-enter', 'trigger-enter-active')
bg.classList.remove('open')

而滑鼠移入事件為,當滑鼠指到li元素時,加入CSS類別trigger-entertrigger-enter是讓dropdowndisplay轉為block,加入時間150毫秒之後判斷若有trigger-enter類別,再加入trigger-enter-active類別,而trigger-enter-active類別是將不透明度opacity從0到1。

 function handleEnter(){
    this.classList.add('trigger-enter')
    setTimeout(()=>{
      if (this.classList.contains('trigger-enter')) {
        this.classList.add('trigger-enter-active')
      }
    }, 150)
    bg.classList.add('open')

    const dropdown = this.querySelector('.dropdown')
    const dropdownCoords = dropdown.getBoundingClientRect()
    const navCoords = nav.getBoundingClientRect()

    const coords = {
      height: dropdownCoords.height,
      width: dropdownCoords.width,
      top: dropdownCoords.top - navCoords.top,
      left: dropdownCoords.left - navCoords.left,
    }

    bg.style.setProperty('height', `${coords.height}px`)
    bg.style.setProperty('width', `${coords.width}px`)
    bg.style.setProperty('transform', `translate(${coords.left}px, ${coords.top}px)`)
  }

將類別dropdownBackground的元素加入類別open

<div class="dropdownBackground">
  <span class="arrow"></span>
</div>

效果是將類別opendiv元素不透明度設為1。

.dropdownBackground.open {
    opacity: 1;
  }

這時取得滑鼠指定li裡的類別為dropdown的元素的大小和相對位置getBoundingClientRect(),以及nav元素的大小和相對位置。

dropdown的元素的寬、高度加入到類別為opendiv元素中,讓div元素跟dropdown一樣寬、高。

div的X軸位置為dropdown的離螢幕左邊界的距離扣除nav元素離左邊界的距離,Y軸位置為dropdown的離螢幕上邊界的距離扣除nav元素離上邊界的距離,原因為getBoundingClientRect()是取得元素離畫面的距離,但div元素在nav元素中,因此要計算divnav元素中的距離,要扣除navdiv重複的部分,才能得到divnav中的距離。

之後計算出來的距離用transform:translate()來位移divnav元素距離。

這樣就做出效果。

Html

<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>
        <a href="#">Courses</a>
        <ul class="dropdown courses">
          <li>
            <span class="code">RFB</span>
            <a href="https://ReactForBeginners.com">React For Beginners</a>
          </li>
          <li>
            <span class="code">ES6</span>
            <a href="https://ES6.io">ES6 For Everyone</a>
          </li>
          <li>
            <span class="code">STPU</span>
            <a href="https://SublimeTextBook.com">Sublime Text Power User</a>
          </li>
          <li>
            <span class="code">WTF</span>
            <a href="http://flexbox.io">What The Flexbox?!</a>
          </li>
          <li>
            <span class="code">LRX</span>
            <a href="http://LearnRedux.com">Learn Redux</a>
          </li>
          <li>
            <span class="code">CLPU</span>
            <a href="http://CommandLinePowerUser.com">Command Line Power User</a>
          </li>
          <li>
            <span class="code">MMD</span>
            <a href="http://MasteringMarkdown.com">Mastering Markdown</a>
          </li>
        </ul>
      </li>
      <li>
        <a href="#">Other Links</a>
        <ul class="dropdown dropdown3">
          <li><a class="button" href="http://twitter.com/wesbos">Twitter</a></li>
          <li><a class="button" href="http://facebook.com/wesbos.developer">Facebook</a></li>
          <li><a class="button" href="http://wesbos.com">Blog</a></li>
          <li><a class="button" href="http://wesbos.com/courses">Course Catalog</a></li>
        </ul>
      </li>
    </ul>
  </nav>

Javascript

  1. Element.clientHeight
    Element.clientHeight 唯讀屬性會回傳元素內部高度(像素),包含 padding 但並未包含滾動條、border、margin。clientHeight 可以被計算成 CSS height + CSS padding - 滾動條的高度(如果有顯示)

  2. Element.clientWidth
    Element.clientWidth 唯讀屬性會回傳元素內部寬度(像素),包含 padding 但並未包含滾動條、border、margin。clientWidth 可以被計算成 CSS width + CSS padding - 滾動條的高度(如果有顯示)

  1. Element.clientTop
    Element.clientTop為距離上邊界的距離。不包含內距和外距。

  2. Element.clientLeft
    Element.clientLeft為距離左邊界的距離。不包含內距和外距。

  3. Element.scrollHeight
    Element.scrollHeight為元素真實的高度。包含內距。

  4. Element.scrollWidth
    Element.scrollWidth為元素真實的寬度。包含內距。

  1. Element.scrollTop
    Element.scrollTop為元素滾動時離元素上邊界的距離

  2. Element.scrollLeft
    Element.scrollTop為元素滾動時離元素左邊界的距離

  3. HTMLElement.offsetHeight
    HTMLElement.offsetHeight為元素的高度,包含內距,邊界,外距。

  4. HTMLElement.offsetWidth
    HTMLElement.offsetHeight為元素的寬度,包含內距,邊界,外距。

  5. HTMLElement.offsetTop
    HTMLElement.offsetTop為元素左上角距離HTMLElement.offsetParent元素上邊界的距離。

  6. HTMLElement.offsetLeft
    HTMLElement.offsetTop為元素左上角距離HTMLElement.offsetParent元素左邊界的距離。

  7. HTMLElement.offsetParent
    HTMLElement.offsetParent為目標元素的最近定位元素。

CSS

  1. display
    [1]

  2. will-change
    will-change先告訴瀏覽器哪些屬性可以被改變,達到優化的變化。
    The will-change CSS property provides a way for authors to hint browsers about the kind of changes to be expected on an element, so that the browser can set up appropriate optimizations ahead of time before the element is actually changed.

/* Keyword values */
will-change: auto;
will-change: scroll-position;
will-change: contents;
will-change: transform;        /* Example of <custom-ident> */
will-change: opacity;          /* Example of <custom-ident> */
will-change: left, top;        /* Example of two <animateable-feature> */
tags: Element

上一篇
Day25 Event Capture, Propagation, Bubbling and Once
下一篇
Day27 Click and Drag to Scroll
系列文
JavaScript 30實作心得筆記30

尚未有邦友留言

立即登入留言