#12-套件掰!用JS 做进场特效 (Intersection Observer API)

进场特效也是基本再基本的网页动态!
尤其是当网页内容塞太多时,适当地加上进场特效可以帮助使用者阅读重点。

以前常用的套件如Scroll Magic
或计算网页滑动的高度,等到滑到位置时搭配Animate.css做简单进场。
但今天不用套件,我们用 JS的 Web API : Intersection Observer
轻松愉快做出进场特效!

Intersection Observer API 可以非同步侦测目标与其他元素发生交集,
好处就是可以取代过去监听scroll的同步事件(一直监听让网页效能变差)

老样子,先看一下今天的成果:

让我们一步步拆解吧!


观察物件位置:Intersection Observer API

Intersection Observer API可以帮我们观察两个物件是否有交集
这两个物件一定要是父层子层关系,没有设定的话预设都是视窗。

可以搭配服用这一篇,解释得非常清楚!
认识 Intersection Observer API:实作 Lazy Loading 和 Infinite Scroll

流程就是
1.创建新的API
2.设定观察对象
3.设定API选项
4.建立callback-->当两个物件交集的时候要做什麽事情

我们要做的就是当物件(我的图片们)和视窗交集时,
加上animation Class

来看code:

//设定observer api 选项
//root预设就是视窗
const options = {
  rootMargin: '0px 0px 50px 0px',
  threshold: 0
}

//选定要观察的对象
const shapes = document.querySelectorAll('.shape')
const images = document.querySelectorAll('.img')

//设定call back
const callback = (entries, observer) => {
  entries.forEach(entry => {
    if (!entry.isIntersecting) return //如果还没有交集的话就return
    
    entry.target.classList.add('animation');// 近来视窗的话帮我加上animation class
    observer.unobserve(entry.target)
  })
}

//创建新的观察API
let observer = new IntersectionObserver(callback, options);

//所有观察对象都设定观察
images.forEach((target) => {
observer.observe(target)
})

//所有观察对象都设定观察
shapes.forEach((shape) => {
observer.observe(shape)
})

Clip-path进场特效

这次的进场效果使用clip-path做。
搭配这个网站:CSS clip-path maker做出想要的遮罩效果!

原理就是让图片下面都压一层有颜色的区块,
1.然後让遮罩先罩住有颜色的区块
2.再让遮罩照着图片

图片和色块都用一样的animation,但用animation-delay做出时间差

@keyframes image-img{
  from{
    clip-path: polygon(0% 50%, 0% 50%, 0% 50%, 0% 50%);
    opacity: 1;
  }
  to{
    clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
    opacity: 1;
  }
}

看看全部的HTML & SCSS code:

//HTML
<section>
  <div class="img-wrapper">
    <img class="img img-1"src="https://source.unsplash.com/random/640x390?taipei" alt="">
    <img class="img img-2" src="https://source.unsplash.com/random/640x390?taiwan" alt="">
    <img class="img img-3"  src="https://source.unsplash.com/random/640x390?taipei-101" alt="">
    <div class="shape shape-1"></div>
    <div class="shape shape-2"></div>
    <div class="shape shape-3"></div>
    <div class="shape shape-4"></div>
    <div class="shape shape-5"></div>
  </div>
</section>
//scss
.img-wrapper{
  position: relative;
  width: 60%;
  height: 100vh;
  
  .img{
    position: absolute;
    clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
    z-index: 2;
    opacity: 0;
    
    &.animation{
    animation: image-img 0.8s ease-in 1 forwards;
    animation-delay: 1s;
    }
    
    &-1{
      width: 300px;
      left: 0%;
      top:10%;
      z-index: 3;
    }
    &-2{
      width: 600px;
      top: 20%;
      left: 10%;
    }
    &-3{
      width: 400px;
      left: 60%;
      top: 50%;}
    
  }
  
  .shape{
    @extend .img;
    z-index: 1;
    opacity: 0;
    
    &.animation{
      animation: image-img 0.8s ease-in 1 forwards;
      animation-delay: 0s;
    }
    
    &-1{
      @extend .img-1;
      left: 1%;
      top:11%;
      height: calc(300 / 640 * 390px);
      background: rgba(25, 181, 254, 1);
    }
    &-2{
      @extend .img-2;
      top: 21%;
      left: 11%;
      height: calc(600 / 640 * 390px);
      background: rgba(51, 110, 123, 1);
    }
    &-3{
      @extend .img-3;
      left: 61%;
      top: 51%;
      height: calc(400 / 640 * 390px);
      background: rgba(77, 19, 209, 1);
    }
    
    &-4{
      width: 600px;
      height: 30px;
      background: rgba(197, 239, 247, 1);
      left: -10%;
      bottom: 15%;
      clip-path: none;
      animation: none;
      transform: skewY(
-10deg
);
      z-index: 0;
    }
    &-5{
      width: 600px;
      height: 10px;
      background: rgba(34, 167, 240, 1);
      left: -10%;
      bottom: 10%;
      clip-path: none;
      animation: none;
      transform: skewY(
-10deg
);
      z-index: 0;
    }
  }
  
  
}

@keyframes image-img{
  from{
    clip-path: polygon(0% 50%, 0% 50%, 0% 50%, 0% 50%);
    opacity: 1;
  }
  to{
    clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
    opacity: 1;
  }
}

以上!

搭配了昨天向下滑的code,code放这里

有任何问题/错误/想法请留言~~


<<:  [ Day 13 ] React 的生命周期 - Unmounting

>>:  追求JS小姊姊系列 Day13 -- 方函式的能力展现:懂回呼函式才能当好工具人

Swift纯Code之旅 Day4.「画面分身术 - TableView & AutoLayout」

没错!到现在我们已经有了管理画面的TabbarController了, 今天呢,就要来将闹钟页面的画...

前端工程师也能开发全端网页:挑战 30 天用 React 加上 Firebase 打造社群网站|Day20 会员选单

连续 30 天不中断每天上传一支教学影片,教你如何用 React 加上 Firebase 打造社群...

Day16 NodeJS-Express I

从今天开始,程序码和实作练习的部份会占比较多的部份,终於要进入实用的NodeJS网页框架-Expre...

25 | 【进阶教学】什麽是 WordPress 区块小工具?

由於 WordPress 是不停改进的 CMS 系统,它们在 2021 年的 WordPress ...

[C 语言笔记--Day03] 解题纪录:MIN-MEX Cut

题目:MIN-MEX Cut 观察: 当 s 全为 0 时,MEX = 1 当 s 全为 1 时,M...