Javascript小型專案練習15 Slide in on Scroll(JS30-13)

JS30又來啦~!這次處理的是學生時期我們在做簡報時常用的淡入淡出功能,坦白說我同意課程講者說的:這麼做實在看了有點煩躁XD,但我們還是來看一下要如何在JS中實現這樣的功能吧!

HTML

 <body>

  <div class="site-wrap">

    <h1>Slide in on Scroll</h1>

    <p> a long paragraph</p>

    <img src="http://unsplash.it/400/400" class="align-left slide-in">

    <p> a long paragraph </p>

    <img src="http://unsplash.it/400/401" class="align-right slide-in">

    <p>  a long paragraph </p>

    <img src="http://unsplash.it/200/500" class="align-left slide-in">

    <p> a long paragraph </p>


    <p> a long paragraph </p>

    <img src="http://unsplash.it/400/400" class="align-right slide-in">

    <p> a long paragraph </p>
    <p> a long paragraph </p> 

</body>

CSS

    html {
      box-sizing: border-box;
      background: #ffc600;
      font-family: 'helvetica neue';
      font-size: 20px;
      font-weight: 200;
    }

    body {
      margin: 0;
    }

    *,
    *:before,
    *:after {
      box-sizing: inherit;
    }

    h1 {
      margin-top: 0;
    }

    .site-wrap {
      max-width: 700px;
      margin: 100px auto;
      background: white;
      padding: 40px;
      text-align: justify;
    }

    .align-left {
      float: left;
      margin-right: 20px;
    }

    .align-right {
      float: right;
      margin-left: 20px;
    }

    .slide-in {
      opacity: 0;
      transition: all .5s;
    }

    .align-left.slide-in {
      transform: translateX(-30%) scale(0.95);
    }

    .align-right.slide-in {
      transform: translateX(30%) scale(0.95);
    }

    .slide-in.active {
      opacity: 1;
      transform: translateX(0%) scale(1);
    } 

Javascript

function debounce(func, wait = 20, immediate = true) {
      var timeout;
      return function () {
        var context = this, args = arguments;
        var later = function () {
          timeout = null;
          if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
      };
  }

  // 建立滑動函數
  function scroll(e) {
      slideImages.forEach(image => {
        /*
window.screenY+window.innerHeight會給出目前滑到的位置,可以注意outerHeight & innerHeight的差別,由於我們希望滑到圖片一半時就顯示圖片,於是在後方在減掉圖片一半的高度
        */

        const slideInAt = (window.scrollY + window.innerHeight) - image.height / 2

        /*
滑過圖片時要讓它恢復原狀,需要找出圖片的底部,offsetTop會找出圖片的頂端與頁面最上方的距離
我們希望找到的是圖片的底部,所以還需要再加上圖片的長度
        */

        const imageBottom = image.offsetTop + image.height;
        const isHalfShown = slideInAt > image.offsetTop;
        const isNotScrollPassed = window.scrollY < imageBottom;
        isHalfShown && isNotScrollPassed ? image.classList.add('active') : image.classList.remove('active')
      })
    }

    // 事件監聽
    const slideImages = document.querySelectorAll('.slide-in')


    window.addEventListener('scroll', debounce(scroll)) function debounce(func, wait = 20, immediate = true) {
      var timeout;
      return function () {
        var context = this, args = arguments;
        var later = function () {
          timeout = null;
          if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
      };
  }

 

學習重點

  • 了解如何運用scrollY、offsetTop找出元素或游標的位置
  • 了解innerHeight & outerHeight的差別
  • 了解為何使用debounce()->阻止事件無意義的重複執行而影響到效能
  • 複習利用JS替元素套用CSS樣式的方法

參考文章

MDN window.innerHeight

發表留言