GSAP ã® ScrollTrigger.batch
ã使ãã°ããªã¹ããªã©ã«ç°¡åã«ã¢ãã¡ã¼ã·ã§ã³ãè¨å®ãããã¨ãã§ããã
https://gsap.com/docs/v3/Plugins/ScrollTrigger/static.batch()/
batch ã§ã¢ãã¡ã¼ã·ã§ã³ãè¨å®ããã¨ãã«ãã¢ãã¡ã¼ã·ã§ã³ãå®è¡ãããè¦ç´ ã« class ãä»ãããã¨ããè¦ç´ ã«ä½ãå¦çããããè¦æããã£ãã®ã§ãã®ã¡ã¢
- TypeScript:
^5.5.4
- GSAP:
^3.12.5
ScrollTrigger.batch ã使ã£ãã¢ãã¡ã¼ã·ã§ã³ã®åºæ¬
cf. static-batch | GSAP | Docs & Learning
import gsap from 'gsap'; import { ScrollTrigger } from 'gsap/ScrollTrigger'; gsap.registerPlugin(ScrollTrigger); // ã¢ãã¡ã¼ã·ã§ã³ãããè¦ç´ ã®è¡¨ç¤ºãåæå gsap.set(".listItem", { autoAlpha: 0, y: 50 }); ScrollTrigger.batch('.listItem', { interval: 0.1, // ãããå¦çãè¡ãããã¾ã§ã®æé (ç§) start: "top-=200 center", // ã¿ã¼ã²ããã® top - 200px ã«ç»é¢ã®ä¸å¤®ãæ¥ããéå§ end: "bottom+=50 center" // ã¿ã¼ã²ããã® bottom + 50px ã«ç»é¢ã®ä¸å¤®ãæ¥ããçµäº once: true, // ä¸åº¦ã ãå®è¡ãã markers: true, // debug ç¨ã« start, end ã®ã¬ã¤ãã表示ããã onEnter: (elements) => { // onEnter å ã§ã¢ãã¡ã¼ã·ã§ã³ã®è¨å®ããã gsap.to(elements, { stagger: 0.5, // åããããå ã§ã¢ãã¡ã¼ã·ã§ã³ãå®è¡ãããã¨ãã®æå·® autoAlpha: 1, y: 0, }); }, });
対象è¦ç´ ã« class åãä»ãããã ããªã attr
ã便å©
ä¾ãã°ã¢ãã¡ã¼ã·ã§ã³ãå§ã¾ã£ãéã« isLoaded
ã¯ã©ã¹ãä»ããdata-status="loaded"
ã«ãããªãä¸è¨ã®ãããªæã
ScrollTrigger.batch('.listItem', { interval: 0.1, start: "top-=200 center", end: "bottom+=50 center" once: true, markers: true, onEnter: (elements) => { gsap.to(elements, { stagger: 0.5, autoAlpha: 1, y: 0, // attr ã¯å®å ¨ã«ç½®æããã®ã§å ã®ã¯ã©ã¹åãæ®ãå¿ è¦ããããªãæ¸ãã¦ãã attr: { class: ".listItem .isLoaded", "data-status": "loaded" } }); }, });
â ï¸ attr
ã®æ³¨æç¹
- attribute ãã¾ãã£ã¨ç½®æãã¦ãã¾ãã®ã§ãå¿ è¦ãªãã®ã¯è¨è¿°ããå¿ è¦ããã HTML ã¨å¯çµåã«ãªã£ã¦ãã¾ã
attr
㯠trigger ã«ãªã£ã¦ããè¦ç´ ãã対象ã«ããªãã®ã§ãåè¦ç´ ã親è¦ç´ ã«ãªã«ããããå ´åã¯å¯¾å¿ã§ããªã (CSSã§å¯¾å¿ã§ããç¯å²ã§ããæä½ã§ããªã)- æååãè¿ãé¢æ°ãè¨ç½®ã§ããããããã¥ã¡ã³ãã«ã¯æ¸ããã¦ãªãã®ã§åä½ã¯æ ä¿ããã¦ãªããã
ScrollTrigger.batch('.listItem', { // ç¥ onEnter: (elements) => { gsap.to(elements, { stagger: 0.5, autoAlpha: 1, y: 0, attr: { class: (_index, item) => { const cx = item.classList.value; return cx + ' isLoaded'; }, }, }); }, });
â ãããåä½ããããããã¥ã¡ã³ãã«ãã®æ¹æ³ã¯è¼ã£ã¦ãªãã£ã½ãã®ã§åä½ä¿è¨¼ã¯ãªããã
ð 1度ã ã対象è¦ç´ 以å¤ãæä½ãããªã onEnter
å
ã® gsap.to
å
ã«ã¤ãã³ããè¨å®ããã®ãè¯ããã
å¾è¿°ããããonToggle
㯠start, end ãè·¨ã度ã«å®è¡ãããonLeave
ã¯ã¹ã¯ãã¼ã«é度ã§ã¯çºç«ããªãã±ã¼ã¹ããã£ãã
onEnter
ããããã°ã¢ãã¡ã¼ã·ã§ã³ã¯çºç«ããã®ã§ããã®ä¸ã§æä½ããå¦çãæ¸ãã¦ãã¾ãã®ã確å®ããªã¨ããå°è±¡
ScrollTrigger.batch('.listItem', { // ç¥ onEnter: (elements) => { gsap.to(elements, { stagger: 0.5, autoAlpha: 1, y: 0, // attr ã¯ç½®æã§æ±ãã¥ããã®ã§ä½¿ããªã // attr: { class: ".listItem .isLoaded", "data-status": "loaded" } }, onStart: (index, item) => { // ã¢ãã¡ã¼ã·ã§ã³ãéå§ãããæç¹ã§å®è¡ããã item?.classList.add('isLoaded'); item?.dataset.status = 'loaded'; const parent = item?.parentElement; parent?.classList.add('isChildLoaded'); }, onLeave: (index, item) => { // gsap.to ã®è¨å®çã« end ãç¡ãã®ã§ onStart ç´å¾ã«çºç«ããã®ã§ä½¿ãåããæå³ã¯ã»ã¼ç¡ã }, onComplete: (arg: undefined) => { // ãããã§å®è¡ãããã¢ãã¡ã¼ã·ã§ã³ãå ¨ã¦å®äºãããå¼ã³åºãããããå¼æ°ã `undefined` ãªã®ã§ä½¿ãã¥ãã }, }); }, });
onComplete
onComplete
ã¯ãããã«ãªã£ã¦ããã¢ãã¡ã¼ã·ã§ã³ãå
¨ã¦å®äºãããå¼ã³åºãããã®ã§ä¾¿å©ã ããå¼æ°ãç¡ãã®ã§æ±ãã¥ãã
Arrow function ã§ã¯ãªãé常ã®é¢æ°ã«ãããã¨ã§ this
ãã対象ãå¼ã£å¼µã£ã¦ãããã¨ãã§ããã _target
ã¨ããã¢ã³ãã¼ã¹ã³ã¢ä»ãã®ããããã£ãªã®ã§ãã¢ã³ããã¿ã¼ã³ã§ã¯ãªããã¨æãã(æä½ã§ããã«ã¯ã§ãã)
ScrollTrigger.batch('.listItem', { // ç¥ onEnter: (elements) => { gsap.to(elements, { stagger: 0.5, autoAlpha: 1, y: 0, // attr ã¯ç½®æã§æ±ãã¥ããã®ã§ä½¿ããªã // attr: { class: ".listItem .isLoaded", "data-status": "loaded" } }, onStart: (index, item) => { // ã¢ãã¡ã¼ã·ã§ã³ãéå§ãããæç¹ã§å®è¡ããã item?.classList.add('isLoaded'); item?.dataset.status = 'loaded'; const parent = item?.parentElement; parent?.classList.add('isChildLoaded'); }, onComplete: function() { const self = this; const elemens = self?._targets; if ( !Array.isArray(elemens) ) { return; } elemens.forEach((el) => { if (!el || el instanceof HTMLElement === false) { return; } el.classList.add('isComplete'); el.dataset.status = 'complete'; }); } }); }, });
ð¤ è¦ç´ ãæä½ãããå ´å㯠onToggle
ã使ãã
ã¢ãã¡ã¼ã·ã§ã³ãå§ã¾ã£ãéã«è¦ªè¦ç´ ã« isLoaded
ã¯ã©ã¹ãä»ããåè¦ç´ ã®data-status
å±æ§ãã loaded
ã«ãããªãä¸è¨ã®ãããªæã
ãã ããonToggle
㯠start, end ãè·¨ãã ã¿ã¤ãã³ã°ã§å®è¡ãããã®ã§ 1åã ãå®è¡ãããããããªã±ã¼ã¹ã§ã¯å·¥å¤«ãå¿
è¦
ScrollTrigger.batch('.listItem', { // ç¥ onEnter: (elements) => { // onEnter å ã§å .listItem ã®ã¢ãã¡ã¼ã·ã§ã³ãè¨å® gsap.to(elements, { stagger: 0.5, autoAlpha: 1, y: 0, }); }, onToggle: (elements) = > { // ä»åã®ãããã§å®è¡ãããè¦ç´ ã®é åãå¼æ°ã¨ãã¦æ¸¡ããã elements.forEach((el) = > { const parent = el.parentElement; const child = el.firstElementChild; parent?.classList.add("isLoaded"); child?.dataset.status = "loaded"; }); }, });
â ï¸ onToggle
ã®æ³¨æç¹
onToggle
㯠start, end ãã¾ãã度ã«å®è¡ãããã®ã§ã1度ã ãæä½ãããã»çµäºæã«æä½ãããå ´åã¯æ±ãã«æ³¨æãå¿ è¦once
ã®ã¨ãã¹ã¯ãã¼ã«é度ãæ©ãã¨onToggle
ã¯å®è¡ãããªãã±ã¼ã¹ããã£ãã®ã§ç¢ºå®æ§ã¯å¾®å¦
ð¤ 対象ããã¹ã¯ãã¼ã«ãåºãéã«ä½ãå®è¡ãããªã onLeave
å
¬å¼ããã¥ã¡ã³ãã«ä¾ãè¼ã£ã¦ãã onLeave
ã¯ãããã®å¯¾è±¡ããåºãæã«å®è¡ãããã®ã§ãã¢ãã¡ã¼ã·ã§ã³ãå®äºããå¾ã«è¦ç´ ã«å¯¾ãã¦ä½ãå¦çãè¡ãéã«ä½¿ãã
ScrollTrigger.batch('.listItem', { // ç¥ onEnter: (elements) => { // onEnter å ã§å .listItem ã®ã¢ãã¡ã¼ã·ã§ã³ãè¨å® gsap.to(elements, { stagger: 0.5, autoAlpha: 1, y: 0, }); }, onLeave: (elements) = > { // 対象å¤ã«ãªã£ããããã«å«ã¾ããè¦ç´ ã®é åãå¼æ°ã¨ãã¦æ¸¡ããã elements.forEach((el) = > { el.dataset.status = "leaved"; const parent = el.parentElement; parent?.classList.add("isLeaved"); }); }, });
â ï¸ onLeave
ã®æ³¨æç¹
- ã¹ã¯ãã¼ã«é度ã«ãã£ã¦ã¯çµæ§ãªç¢ºçã§çºç«ããªããæè¦çã« end ã®
onToggle
ã®æ¹ãã¾ã çºç«ãããå¯è½æ§ãé«ãæ°ããã onEnter
ããã¢ãã¡ã¼ã·ã§ã³ã®æéå setTimeout ãããã»ãã確å®æ§ã¯ãããã
ð
onStart
, onComplete
㯠ScrollTrigger.batch
ã«ã¯ãªã
Timeline .vars ã« onStart
, onComplete
ã®é
ç®ããã£ãããScrollTrigger.batch
ã§ã¯ onStart
, onComplete
ã¯çºç«ããªãã£ã½ã (â» ScrollTrigger .vars ã®ããã¥ã¡ã³ããèã vars ã®ä¸èº«ã¯åãã ã¨æã£ã¦ããã)
対象è¦ç´ ãè¤æ°ãªã®ã§ãä½ããã£ã¦ start ãªã®ã complete ãªã®ãå¤æãé£ããã®ã§ä½¿ããªãã®ã¯åãããªãããªã
ScrollTrigger.batch('.listItem', { // ç¥ onEnter: (elements) => { // onEnter å ã§å .listItem ã®ã¢ãã¡ã¼ã·ã§ã³ãè¨å® gsap.to(elements, { stagger: 0.5, autoAlpha: 1, y: 0, }); }, // onStart, onComplete ã¯çºç«ãããªãã£ã onStart: (evt: any) => { console.log('onStart', evt); }, onComplete: (evt: any) => { console.log('onComplete', evt); }, });
ScrollTrigger.batch ã§ã¢ãã¡ã¼ã·ã§ã³å®è¡æã«è¦ç´ ã«å¤æ´ãå ãããã¨ãã®ã¾ã¨ã
onEnter
å ã§å®è¡ããã®ãç¡é£once: true
ã®ã¨ããonToggle
,onLeave
ã¯ã¹ã¯ãã¼ã«é度ã«ãã£ã¦ã¯çºç«ãããªãå ´åãããonEnter
,onToggle
ã¨onLeave
,onToggle
ã®é çªã¯æ ä¿ãããªãattr
,onToggle
ã®çºç«é ãæ ä¿ããã¦ãªã
onToggle
㯠start æ㨠end æã«å®è¡ããã- end ã«ãªãåã« start ãéæ¹åã«ã¹ã¯ãã¼ã«ãã¦è·¨ãã§ãå度å®è¡ããã
- class åã追å ãããã ããªã
attr
ã便å©ã ããclass åãã¾ãã£ã¨ç½®æãã¦ãã¾ãã®ã§æ³¨æãå¿ è¦attr
ã¯å¯¾è±¡ã®è¦ç´ ããæä½ã§ããªãã®ã§ã親ãåè¦ç´ ãªã©å¯¾è±¡è¦ç´ ãèµ·ç¹ã«ä»ã®è¦ç´ ãæä½ãããå ´åã¯å¥ã®ã¢ããã¼ããå¿ è¦attr
ã® value ã«æååãè¿ãé¢æ°ãè¨å®ã§ãããããã¥ã¡ã³ãã«è¼ã£ã¦ãªãã®ã§åä½ãæ ä¿ããããã¯æªãã
- ã¢ãã¡ã¼ã·ã§ã³å®äºæã«ä½ãããããã®ã§ããã°
onEnter
å ã§ã¢ãã¡ã¼ã·ã§ã³ã®æéåsetTimeout
ãããã®ãç¡é£ãã (å¾®å¦ã ãã©) - onLoad æã«ãæ¢ã«ã¢ãã¡ã¼ã·ã§ã³ãçµäºãã¦ããã¹ã¯ãã¼ã«ä½ç½®ã®å ´åã¯ãã¹ã¯ãã¼ã«éã¨ã³ã³ãã³ãã®ä½ç½®ãã GSAP ãåä½ãããå®äºã¨ãããå¦çãæãã»ããè¯ããã
Sample
â ã¹ã¯ãã¼ã«ãä¸ä¸ããã㨠once: true
ã§ã end ã«å°éããåã« start ãè·¨ã度㫠onToggle
ãå®è¡ãããã®ã確èªã§ãã
See the Pen GSAP batch animation callback by KIKIKI (@kikiki_kiki) on CodePen.
batch ã§ã¢ãã¡ã¼ã·ã§ã³ãéå§ãããè¦ç´ ã¨ããã®è¦ç´ ãèµ·ç¹ã« DOM æä½ãããã£ãã ãã ã£ããã ãã©ãçµæ§æ²¼ã ã£ãã
ããã¦ããã®ã㨠ScrollTrigger.batch
使ããªãã¦ãã§ããããã⦠ã¨ãªã£ã¦ãã¾ã£ã訳ã§ãããããã¯ã¾ãå¥ã®ã話â¦
ããã。ï¾(ï¾ âá´âï¾)ï¾ï½¡
[åè]