ส่วนประกอบปฏิกิริยาเคลื่อนไหวด้วย GreenSock

เผยแพร่แล้ว: 2022-03-10
สรุปอย่างย่อ ↬ GreenSock Animation Platform (GSAP) เป็นชุดฟังก์ชัน JavaScript ที่ให้คุณปรับแต่งคุณสมบัติค่า/แอตทริบิวต์/CSS เมื่อเวลาผ่านไป และแทรก Tweens เหล่านี้ลงในไทม์ไลน์สำหรับแอนิเมชั่นที่ซับซ้อนมากขึ้น ในบทความนี้ Blessing อธิบายวิธีที่ GSAP เล่นได้ดีกับไลบรารี React โดยการรวมฟังก์ชันเข้ากับส่วนประกอบ React ในการสร้างหน้า Landing Page ตัวอย่างที่มีแอนิเมชั่นต่างๆ

ในช่วงแรกๆ ของเวิลด์ไวด์เว็บ สิ่งต่างๆ ค่อนข้างนิ่งและน่าเบื่อ หน้าเว็บส่วนใหญ่ใช้การออกแบบกราฟิกและเลย์เอาต์จากโลกแห่งการพิมพ์จนกระทั่งมีการแนะนำแอนิเมชั่น แอนิเมชั่นสามารถดึงดูดและดึงความสนใจของผู้คนได้นานกว่าหน้าเว็บแบบคงที่ และสื่อสารแนวคิดหรือแนวคิดได้อย่างชัดเจนและมีประสิทธิภาพมากขึ้น

อย่างไรก็ตาม เมื่อทำไม่ถูกต้อง แอนิเมชั่นอาจขัดขวางการโต้ตอบของผู้ใช้กับผลิตภัณฑ์ของคุณและส่งผลเสียต่อการดึง GreenSock Animation Platform AKA (GSAP) เป็นไลบรารี JavaScript อันทรงพลังที่ช่วยให้นักพัฒนาฟรอนต์เอนด์ แอนิเมเตอร์ และนักออกแบบสามารถสร้างแอนิเมชั่นตามไทม์ไลน์ได้อย่างมีประสิทธิภาพ ช่วยให้ผู้ชื่นชอบแอนิเมชั่นสามารถควบคุมลำดับแอนิเมชั่นได้อย่างแม่นยำ มากกว่าที่จะจำกัดคุณสมบัติของ keyframe และ animation ในบางครั้งที่ CSS นำเสนอ

ในบทความนี้ ผมจะแนะนำให้คุณรู้จักกับคุณสมบัติบางอย่างของ GSAP เช่น scrollTriggers , Timelines , Easing ฯลฯ ในตอนท้าย เราจะสร้างอินเทอร์เฟซผู้ใช้ที่ใช้งานง่ายโดยทำให้แอป React เคลื่อนไหวด้วยคุณสมบัตินี้ ตรวจสอบโครงการที่เสร็จสิ้นใน codesandbox

บทความนี้จะเป็นประโยชน์กับคุณหาก:

  • คุณได้สร้างแอนิเมชั่นบนเว็บแอปพลิเคชันด้วย HTML, CSS และ JavaScript
  • คุณกำลังสร้างเว็บเพจแอนิเมชั่นในแอป React ด้วยแพ็คเกจต่างๆ เช่น animate.css, React-motion, Framer-motion และ React-Spring รวมทั้งคุณต้องการดูทางเลือกอื่น
  • คุณเป็นคนที่คลั่งไคล้ React และคุณต้องการสร้างแอนิเมชั่นที่ซับซ้อนบนเว็บแอปพลิเคชันที่ใช้ React

เราจะมาดูวิธีสร้างแอนิเมชั่นที่หลากหลายจากโปรเจ็กต์เว็บที่มีอยู่ ไปกันเถอะ!

หมายเหตุ : บทความนี้ถือว่าคุณคุ้นเคยกับ HTML, CSS, JavaScript และ React.js

GSAP คืออะไร?

GreenSock Animation Platform หรือที่เรียกว่า GSAP เป็นแอนิเมชั่นระดับมืออาชีพที่มีประสิทธิภาพสูงเป็นพิเศษสำหรับเว็บสมัยใหม่ที่ช่วยให้นักพัฒนาสร้างแอนิเมชั่นแอปของตนในรูปแบบโมดูลาร์ ประกาศ และนำกลับมาใช้ใหม่ได้ เป็นเฟรมเวิร์กที่ไม่เชื่อเรื่องพระเจ้าและใช้ได้กับโปรเจ็กต์ที่ใช้ JavaScript ทุกโปรเจ็กต์ มีขนาดบันเดิลที่น้อยที่สุดและจะไม่ทำให้แอปของคุณใหญ่โต

GSAP สามารถทำแอนิเมชั่นแคนวาส ใช้เพื่อสร้างประสบการณ์ WebGL และสร้างแอนิเมชั่น SVG แบบไดนามิก และรองรับเบราว์เซอร์ที่ยอดเยี่ยม

เพิ่มเติมหลังกระโดด! อ่านต่อด้านล่าง↓

ทำไมต้องใช้ GSAP?

บางทีคุณอาจยังไม่พร้อมที่จะหักหลังกรอบงานอื่นๆ หรือคุณยังไม่มั่นใจว่าจะยอมรับสิ่งดีๆ ที่มาพร้อมกับ GSAP ให้ฉันให้เหตุผลสองสามข้อว่าทำไมคุณจึงอาจต้องการพิจารณา GSAP

คุณสามารถสร้างแอนิเมชั่นที่ซับซ้อนได้

ไลบรารี JavaScript ของ GSAP ทำให้นักพัฒนาสามารถสร้างแอนิเมชั่นจากฟิสิกส์ที่เรียบง่ายไปจนถึงซับซ้อนได้ เช่น ในกรณีของไซต์เหล่านี้ ช่วยให้นักพัฒนาและนักออกแบบจัดลำดับการเคลื่อนไหวและควบคุมแอนิเมชั่นแบบไดนามิก มีปลั๊กอินมากมาย เช่น DrawSVGPlugin, MorphSVGPlugin และอื่นๆ ซึ่งทำให้การสร้างแอนิเมชั่นที่ใช้ SVG และแอนิเมชั่น 2D/3D เป็นจริง นอกจากการผสานรวม GSAP บนองค์ประกอบ DOM แล้ว คุณยังสามารถใช้พวกมันภายในแอนิเมชั่นตามบริบทของ WebGL/Canvas/ Three.js

นอกจากนี้ ความสามารถในการค่อยๆ เปลี่ยนของ GSAP นั้นค่อนข้างซับซ้อน ดังนั้นจึงทำให้สามารถสร้างเอฟเฟกต์ขั้นสูงด้วยเบซิเยร์หลายตัว เมื่อเทียบกับแอนิเมชั่น CSS ปกติ

ผลงาน

GSAP มีประสิทธิภาพสูงที่น่าประทับใจในเบราว์เซอร์ต่างๆ

ตามที่ทีมของ GSAP ระบุไว้ในเว็บไซต์ว่า "GSAP เร็ว กว่า jQuery ถึง 20 เท่า และ GSAP เป็นเครื่องมือสร้างภาพเคลื่อนไหวแบบสคริปต์ที่มีคุณสมบัติครบถ้วนเร็วที่สุดในโลก มันเร็วกว่าภาพเคลื่อนไหวและการเปลี่ยน CSS3 ในหลายกรณี” ยืนยันการเปรียบเทียบความเร็วด้วยตัวคุณเอง

นอกจากนี้ แอนิเมชั่น GSAP ยังทำงานได้อย่างง่ายดายทั้งบนคอมพิวเตอร์เดสก์ท็อป แท็บเล็ต และสมาร์ทโฟน ไม่จำเป็นต้องเพิ่มรายการคำนำหน้ายาวๆ ทั้งหมดนี้อยู่ภายใต้การดูแลของ GSAP

คุณสามารถตรวจสอบประโยชน์เพิ่มเติมเกี่ยวกับ GSAP หรือดูว่า Sarah Drasner พูดถึงเรื่องนี้อย่างไรที่นี่

ข้อเสียของ GSAP

คุณกำลังพูดว่าฉันควรใช้ GSAP เสมอสำหรับทุกโครงการหรือไม่ แน่นอนไม่! ฉันรู้สึกว่า มีเหตุผลเดียวที่คุณไม่ต้องการใช้ GSAP มาหาคำตอบกัน!

  • GSAP เป็นเพียงไลบรารีแอนิเมชั่นที่ใช้ JavaScript เท่านั้น ดังนั้นจึงต้องมีความรู้เกี่ยวกับการจัดการ JavaScript และ DOM เพื่อใช้ประโยชน์จากวิธีการและ API อย่างมีประสิทธิภาพ ข้อเสียของเส้นโค้งการเรียนรู้นี้ทำให้มีพื้นที่ว่างมากขึ้นสำหรับความยุ่งยากสำหรับผู้เริ่มต้นที่เริ่มต้นด้วย JavaScript
  • GSAP ไม่รองรับแอนิเมชั่นที่ใช้ CSS ดังนั้น หากคุณกำลังมองหาไลบรารีสำหรับสิ่งนี้ คุณอาจใช้ keyframes ในแอนิเมชั่น CSS ได้เช่นกัน

หากคุณมีเหตุผลอื่นใด โปรดแชร์ในส่วนความคิดเห็น

เอาล่ะ เมื่อคลายข้อสงสัยของคุณแล้ว ไปที่ประเด็นสำคัญใน GSAP กัน

ข้อมูลพื้นฐาน GSAP

ก่อนที่เราจะสร้างแอนิเมชั่นโดยใช้ React เรามาทำความคุ้นเคยกับวิธีการและองค์ประกอบพื้นฐานของ GSAP กันก่อน

หากคุณทราบพื้นฐานของ GSAP แล้ว คุณสามารถข้ามส่วนนี้และข้ามไปยังส่วนโครงการโดยตรง ซึ่งเราจะทำให้หน้า Landing Page เอียงขณะเลื่อน

ทวีน

ทวีตคือการเคลื่อนไหวครั้งเดียวในแอนิเมชั่น ใน GSAP ทวีตมีไวยากรณ์ต่อไปนี้:

 TweenMax.method(element, duration, vars)

มาดูกันว่าไวยากรณ์นี้หมายถึงอะไร

  1. method หมายถึงวิธี GSAP ที่คุณต้องการใช้
  2. element คือองค์ประกอบที่คุณต้องการทำให้เคลื่อนไหว หากคุณต้องการสร้าง tweens สำหรับองค์ประกอบหลายรายการพร้อมกัน คุณสามารถส่งผ่านอาร์เรย์ขององค์ประกอบไปยัง element
  3. duration คือระยะเวลาของทวีตของคุณ เป็นจำนวนเต็มในหน่วย s (ไม่มีส่วนต่อท้าย!)
  4. vars เป็นวัตถุของคุณสมบัติที่คุณต้องการทำให้เคลื่อนไหว เพิ่มเติมเกี่ยวกับเรื่องนี้ในภายหลัง

วิธี GSAP

GSAP มีวิธีการมากมายในการสร้างแอนิเมชั่น ในบทความนี้เราจะพูดถึงเพียงไม่กี่อย่างเช่น gsap.to , gsap.from , gsap.fromTo คุณสามารถตรวจสอบวิธีการเจ๋ง ๆ อื่น ๆ ได้ในเอกสารประกอบ วิธีการที่กล่าวถึงในส่วนนี้จะถูกนำมาใช้ในการสร้างโครงการของเราในภายหลังในบทช่วยสอนนี้

  • gsap.to() ค่าที่วัตถุควรเคลื่อนไหว เช่น ค่าคุณสมบัติสิ้นสุดของวัตถุที่เคลื่อนไหว ดังที่แสดงด้านล่าง:
     gsap.to('.ball', {x:250, duration: 5})

เพื่อสาธิตวิธีการ to การสาธิต codepen ด้านล่างแสดงให้เห็นว่าองค์ประกอบที่มีคลาสของ ball 250px จะเคลื่อนที่ผ่าน x-axis ในห้าวินาทีเมื่อส่วนประกอบติดตั้ง หากไม่ระบุระยะเวลา ระบบจะใช้ค่าเริ่มต้น 500 มิลลิวินาที

ดูปากกา [GSAP REACT DEMO1](https://codepen.io/smashingmag/pen/LYNrzMB) โดย Blessing Krofegha

ดู Pen GSAP REACT DEMO1 โดย Blessing Krofegha

หมายเหตุ : แกน x และ y-axis นอนและแนวตั้งตามลำดับ นอกจากนี้ในคุณสมบัติการแปลง CSS เช่น translateX และ translateY จะแสดงเป็น x และ y สำหรับการแปลง pixel-measured และ xPercent และ yPercent สำหรับการแปลงแบบเปอร์เซ็นต์

หากต้องการดูส่วนย่อยทั้งหมดของรหัส ให้ตรวจสอบสนามเด็กเล่นของรหัส

  • gsap.from() — กำหนดค่าที่อ็อบเจกต์ควรเคลื่อนไหวจาก — เช่น ค่าเริ่มต้นของแอนิเมชั่น:
     gsap.from('.square', {duration:3, scale: 4})

การสาธิต codepen แสดงให้เห็นว่าองค์ประกอบที่มีคลาสของ square นั้นถูกปรับขนาดจากมาตราส่วน 4 ใน 3seconds เมื่อส่วนประกอบติดตั้งอย่างไร ตรวจสอบข้อมูลโค้ดที่สมบูรณ์บน Codepen นี้

ดูปากกา [GSAP REACT DEMO2](https://codepen.io/smashingmag/pen/bGpKoPV) โดย Blessing Krofegha

ดู Pen GSAP REACT DEMO2 โดย Blessing Krofegha
  • gsap.fromTo() — ให้คุณกำหนดค่าเริ่มต้นและสิ้นสุดสำหรับแอนิเมชั่น เป็นการผสมผสานระหว่างเมธอด from() และ to()

นี่คือลักษณะที่ปรากฏ;

 gsap.fromTo('.ball',{opacity:0 }, {opacity: 1 , x: 200 , duration: 3 }); gsap.fromTo('.square', {opacity:0, x:200}, { opacity:1, x: 1 , duration: 3 });

รหัสนี้จะทำให้องค์ประกอบเคลื่อนไหวด้วยคลาสของ ball จากความทึบ 0 ถึงความทึบ 1 ข้าม x-axis ใน 3 seconds และคลาสส square ร์จะเคลื่อนไหวจากความทึบ 0 ถึง 1 ใน 3 seconds ข้าม x-axis เฉพาะเมื่อส่วนประกอบติดตั้ง หากต้องการดูว่าเมธอด fromTo ทำงานอย่างไรและข้อมูลโค้ดทั้งหมด ให้ตรวจดูการสาธิตใน CodePen ด้านล่าง

ดูปากกา [สาธิต GSAP FromTo](https://codepen.io/smashingmag/pen/WNwyXex) โดย Blessing Krofegha

ดูการสาธิต Pen React GSAP FromTo โดย Blessing Krofegha

หมายเหตุ : เมื่อใดก็ตามที่เราสร้างภาพเคลื่อนไหวคุณสมบัติตำแหน่ง เช่น left และ top เราต้องแน่ใจว่าองค์ประกอบที่เกี่ยวข้องจะต้องมีคุณสมบัติตำแหน่ง CSS ของ relative , absolute หรือ fixed

ผ่อนปรน

เอกสารอย่างเป็นทางการของ GSAP กำหนดว่าการค่อยๆ เปลี่ยนเป็นวิธีหลักในการเปลี่ยนระยะเวลาของ Tweens ของคุณ กำหนดว่าวัตถุเปลี่ยนตำแหน่งอย่างไรในจุดต่างๆ ความง่ายควบคุมอัตราการเปลี่ยนแปลงของแอนิเมชันใน GSAP และใช้เพื่อกำหนดรูปแบบของแอนิเมชั่นของออบเจ็กต์

GSAP มอบความง่ายดายและตัวเลือกประเภทต่างๆ เพื่อให้คุณควบคุมลักษณะการทำงานของแอนิเมชั่นได้มากขึ้น นอกจากนี้ยังมี Ease Visualizer เพื่อช่วยคุณเลือกการตั้งค่าความง่ายที่คุณต้องการ

ความง่ายมีอยู่สามประเภทและแตกต่างกันไปในการใช้งาน

  1. in() — การเคลื่อนไหวเริ่มอย่างช้าๆ แล้วเร่งความเร็วไปยังจุดสิ้นสุดของแอนิเมชั่น
  2. out() — แอนิเมชั่นเริ่มต้นอย่างรวดเร็วแล้วช้าลงเมื่อสิ้นสุดแอนิเมชั่น
  3. inOut() — แอนิเมชั่นเริ่มช้า เร่งความเร็วครึ่งทาง และสิ้นสุดอย่างช้าๆ

ดูปากกา [สาธิตการทำ GSAP Easing](https://codepen.io/smashingmag/pen/abNKLaE) โดย Blessing Krofegha

ดูการสาธิต Pen React GSAP Easing โดย Blessing Krofegha

ในตัวอย่างการค่อยๆ เปลี่ยนเหล่านี้ เราเชื่อมโยง tweens ที่แสดงการง่าย ๆ สามประเภท bounce.in , bounce.out และ bounce.inOut และตั้งค่าการหน่วงเวลาเป็นจำนวนวินาทีที่แอนิเมชั่นต้องทำให้เสร็จก่อนเริ่มอันถัดไปก็ต่อเมื่อ ส่วนประกอบคือเมานต์ รูปแบบนี้ซ้ำซาก ในหัวข้อถัดไป เราจะมาดูกันว่าเราจะใช้ไทม์ไลน์เพื่อทำให้ดีขึ้นได้อย่างไร

ไทม์ไลน์

ไทม์ไลน์ ทำหน้าที่เป็นคอนเทนเนอร์สำหรับทวีตหลายรายการ มันเคลื่อนไหว tweens ตามลำดับ และไม่ขึ้นอยู่กับระยะเวลาของทวีตก่อนหน้า ไทม์ไลน์ทำให้ง่ายต่อการควบคุมทวีตโดยรวมและจัดการเวลาได้อย่างแม่นยำ

สามารถเขียนไทม์ไลน์ได้โดยการสร้างอินสแตนซ์ของไทม์ไลน์ดังนี้:

 gsap.timeline();

คุณยังสามารถโยงทวีคูณทวีคูณกับไทม์ไลน์ได้สองวิธีในโค้ดด้านล่าง:

 ##Method 1 const tl = gsap.timeline(); // create an instance and assign it a variable tl.add(); // add tween to timeline tl.to('element', {}); tl.from('element', {}); ##Method 2 gsap.timeline() .add() // add tween to timeline .to('element', {}) .from('element', {})

มาสร้างตัวอย่างก่อนหน้านี้ด้วยไทม์ไลน์กัน:

 const { useRef, useEffect } = React; const Balls = () => { useEffect(() => { const tl = gsap.timeline(); tl.to('#ball1', {x:1000, ease:"bounce.in", duration: 3}) tl.to('#ball2', {x:1000, ease:"bounce.out", duration: 3, delay:3 }) tl.to('#ball3', {x:1000, ease:"bounce.inOut", duration: 3, delay:6 }) }, []); } ReactDOM.render( , document.getElementById('app')); const { useRef, useEffect } = React; const Balls = () => { useEffect(() => { const tl = gsap.timeline(); tl.to('#ball1', {x:1000, ease:"bounce.in", duration: 3}) tl.to('#ball2', {x:1000, ease:"bounce.out", duration: 3, delay:3 }) tl.to('#ball3', {x:1000, ease:"bounce.inOut", duration: 3, delay:6 }) }, []); } ReactDOM.render( , document.getElementById('app'));

ภายใน useEffect hook เราได้สร้างตัวแปร (tl) ที่เก็บอินสแตนซ์ของไทม์ไลน์ไว้ ต่อไปเราใช้ตัวแปร tl เพื่อทำให้ทวีตของเราเคลื่อนไหวตามลำดับโดยไม่ต้องขึ้นอยู่กับ tween ก่อนหน้าเพื่อทำให้เคลื่อนไหว โดยผ่านคุณสมบัติเดียวกันกับที่อยู่ใน ตัวอย่างก่อนหน้า สำหรับข้อมูลโค้ดที่สมบูรณ์ของการสาธิตนี้ ให้ตรวจสอบสนามเด็กเล่นของ codepen ด้านล่าง

ดู Pen [React GSAP (Easing with Timeline) demo](https://codepen.io/smashingmag/pen/zYqaEmE) โดย Blessing Krofegha

ดูการสาธิต Pen React GSAP (Easing with Timeline) โดย Blessing Krofegha

ตอนนี้เราเข้าใจองค์ประกอบพื้นฐานของ GSAP แล้ว เรามาดูกันว่าเราจะสร้างแอนิเมชั่นที่สมบูรณ์ในแอป React ทั่วไปได้อย่างไรในหัวข้อถัดไป มาเริ่มบินกันเถอะ!

สร้างหน้า Landing Page แบบเคลื่อนไหวด้วย React และ GSAP

มาทำให้แอป React เคลื่อนไหวกันเถอะ ตรวจสอบให้แน่ใจว่าคุณ โคลน repo ก่อนที่คุณจะเริ่มและรันการ npm install เพื่อติดตั้งการพึ่งพา

เรากำลังสร้างอะไร

ปัจจุบัน หน้า Landing Page ของเรามีข้อความสองสามข้อความพื้นหลังสีขาว เมนูที่ไม่ดรอปดาวน์ และไม่มีภาพเคลื่อนไหวจริงๆ ต่อไปนี้คือสิ่งที่เราจะเพิ่มลงในหน้า Landing Page

  • ทำให้ข้อความและโลโก้เคลื่อนไหวบนหน้าแรก ดังนั้นจึงผ่อนคลายเมื่อประกอบส่วนประกอบ
  • ทำให้เมนูเคลื่อนไหว ดังนั้นจึงเลื่อนลงมาเมื่อคลิกเมนู
  • ทำให้รูปภาพในหน้าแกลเลอรีเอียง 20deg เมื่อหน้าเลื่อน
หน้าเคลื่อนไหว
หน้าเคลื่อนไหว

ตรวจสอบการสาธิตบน codesandbox

เราจะแบ่งขั้นตอนของหน้า Landing Page ออกเป็นส่วนประกอบต่างๆ เพื่อให้เข้าใจได้ง่าย นี่คือกระบวนการ

  • กำหนดวิธีการแอนิเมชั่น
  • ข้อความเคลื่อนไหวและโลโก้
  • สลับเมนู
  • ทำให้ภาพเอียง 20deg ในการเลื่อนหน้า

ส่วนประกอบ

  • Animate.js — กำหนดวิธีการแอนิเมชั่นทั้งหมด
  • Image.js — นำเข้ารูปภาพในห้องครัว
  • Menu.js — ประกอบด้วยฟังก์ชันการสลับเมนู
  • Header.js — มีลิงก์การนำทาง

กำหนดวิธีการแอนิเมชั่น

สร้างโฟลเดอร์ component ภายในไดเร็กทอรี src และสร้างไฟล์ animate.js คัดลอกและวางรหัสต่อไปนี้ลงไป

 import gsap from "gsap" import { ScrollTrigger } from "gsap/ScrollTrigger"; //Animate text export const textIntro = elem => { gsap.from(elem, { xPercent: -20, opacity: 0, stagger: 0.2, duration: 2, scale: -1, ease: "back", }); };

ที่นี่เรานำเข้า gsap เราเขียนฟังก์ชันลูกศรที่ส่งออกซึ่งทำให้ข้อความเคลื่อนไหวในหน้า Landing Page จำไว้ว่า gsap.from() กำหนดค่าที่อ็อบเจกต์ควรเคลื่อนไหว ฟังก์ชันนี้มี elem องค์ประกอบที่แสดงถึงคลาสที่ต้องมีการเคลื่อนไหว ใช้คุณสมบัติบางอย่างและกำหนดค่าเช่น xPercent: -20 (แปลงวัตถุ -20%) ทำให้วัตถุไม่มีความทึบ ทำให้ scale วัตถุ -1 ทำให้วัตถุกลับมา ease ใน 2sec

หากต้องการดูว่าใช้งานได้หรือไม่ ตรงไปที่ App.js และใส่รหัสต่อไปนี้

 ... //import textIntro import {textIntro} from "./components/Animate" ... //using useRef hook to access the textIntro DOM let intro = useRef(null) useEffect(() => { textIntro(intro) }, []) function Home() { return ( <div className='container'> <div className='wrapper'> <h5 className="intro" ref={(el) => (intro = el)}></h5> The <b>SHOPPER</b>, is a worldclass, innovative, global online ecommerce platform, that meets your everyday daily needs. </h5> </div> </div> ); }

ที่นี่ เรานำเข้าเมธอด textIntro จากคอมโพเนนต์ Aminate ในการเข้าถึง DOM เราเคยใช้ useRef Hook เราได้สร้าง intro ตัวแปรที่มีค่าตั้งเป็น null ถัดไป ภายใน useEffect hook เราเรียกเมธอด textIntro และตัวแปร intro ภายในองค์ประกอบหลักของเรา ในแท็ก h5 เรากำหนด ref prop และส่งต่อไปในตัวแปร intro

ข้อความเคลื่อนไหว
ข้อความเคลื่อนไหว

ต่อไป เรามีเมนู แต่จะไม่ดรอปดาวน์เมื่อคลิก ให้มันทำงาน! ภายในส่วนประกอบ Header.js ให้เพิ่มโค้ดด้านล่าง

 import React, { useState, useEffect, useRef } from "react"; import { withRouter, Link, useHistory } from "react-router-dom"; import Menu from "./Menu"; const Header = () => { const history = useHistory() let logo = useRef(null); //State of our Menu const [state, setState] = useState({ initial: false, clicked: null, menuName: "Menu", }); // State of our button const [disabled, setDisabled] = useState(false); //When the component mounts useEffect(() => { textIntro(logo); //Listening for page changes. history.listen(() => { setState({ clicked: false, menuName: "Menu" }); }); }, [history]); //toggle menu const toggleMenu = () => { disableMenu(); if (state.initial === false) { setState({ initial: null, clicked: true, menuName: "Close", }); } else if (state.clicked === true) { setState({ clicked: !state.clicked, menuName: "Menu", }); } else if (state.clicked === false) { setState({ clicked: !state.clicked, menuName: "Close", }); } }; // check if out button is disabled const disableMenu = () => { setDisabled(!disabled); setTimeout(() => { setDisabled(false); }, 1200); }; return ( <header> <div className="container"> <div className="wrapper"> <div className="inner-header"> <div className="logo" ref={(el) => (logo = el)}> <Link to="/">SHOPPER.</Link> </div> <div className="menu"> <button disabled={disabled} onClick={toggleMenu}> {state.menuName} </button> </div> </div> </div> </div> <Menu state={state} /> </header> ); }; export default withRouter(Header);

ในองค์ประกอบนี้ เรากำหนดเมนูและสถานะของปุ่ม ภายใน useEffect hook เรารับฟังการเปลี่ยนแปลงของหน้าโดยใช้ useHistory hook หากหน้าเปลี่ยนแปลง เราจะตั้งค่าสถานะการ clicked และ menuName เมนู false และ Menu ตามลำดับ

เพื่อจัดการกับเมนูของเรา เราได้ตรวจสอบว่าค่าของสถานะเริ่มต้นของเราเป็นเท็จ หากเป็นจริง เราจะเปลี่ยนค่าของ initial , clicked และ menuName เป็น null , true และ Close มิฉะนั้น เราจะตรวจสอบว่ามีการคลิกปุ่มหรือไม่ หากเป็นจริง เราจะเปลี่ยน menuName เป็น Menu ต่อไป เรามีฟังก์ชัน disabledMenu ที่จะปิดการใช้งานปุ่มของเราเป็นเวลา 1sec เมื่อมีการคลิก

สุดท้ายนี้ ใน button ของเรา เราได้กำหนดให้ disabled การ disabled ซึ่งเป็นค่าบูลีนที่จะปิดใช้งานปุ่มเมื่อค่าเป็น true และตัวจัดการ onClick ของปุ่มจะเชื่อมโยงกับฟังก์ชัน toggleMenu ทั้งหมดที่เราทำในที่นี้คือสลับข้อความใน menu และส่งสถานะไปยังองค์ประกอบ Menu ซึ่งเราจะสร้างโดยเร็วที่สุด มาเขียนวิธีการที่จะทำให้เมนูของเราดรอปดาวน์ก่อนสร้างองค์ประกอบ Menu จริง ไปที่ Animate.js แล้ววางโค้ดนี้ลงไป

 .... //Open menu export const menuShow = (elem1, elem2) => { gsap.from([elem1, elem2], { duration: 0.7, height: 0, transformOrigin: "right top", skewY: 2, ease: "power4.inOut", stagger: { amount: 0.2, }, }); }; //Close menu export const menuHide = (elem1, elem2) => { gsap.to([elem1, elem2], { duration: 0.8, height: 0, ease: "power4.inOut", stagger: { amount: 0.07, }, }); };

ที่นี่ เรามีฟังก์ชันที่เรียกว่า menuShow ซึ่งจะเอียงเมนูในแนวนอน 2 2degrees ทำให้เมนูง่ายขึ้น ออฟเซ็ตของแอนิเมชั่นโดยใช้คุณสมบัติ stagger และเปลี่ยนเมนูจาก right to top ใน 0.7sec คุณสมบัติเดียวกันจะไปสำหรับฟังก์ชัน menuHide ในการใช้ฟังก์ชันเหล่านี้ ให้สร้างไฟล์ Menu.js ภายใน components แล้ววางโค้ดนี้ลงไป

 import React, {useEffect, useRef} from 'react' import { gsap } from "gsap" import { Link } from "react-router-dom" import { menuShow, menuHide, textIntro, } from './Animate' const Menu = ({ state }) => { //create refs for our DOM elements let menuWrapper = useRef(null) let show1 = useRef(null) let show2 = useRef(null) let info = useRef(null) useEffect(() => { // If the menu is open and we click the menu button to close it. if (state.clicked === false) { // If menu is closed and we want to open it. menuHide(show2, show1); // Set menu to display none gsap.to(menuWrapper, { duration: 1, css: { display: "none" } }); } else if ( state.clicked === true || (state.clicked === true && state.initial === null) ) { // Set menu to display block gsap.to(menuWrapper, { duration: 0, css: { display: "block" } }); //Allow menu to have height of 100% gsap.to([show1, show2], { duration: 0, opacity: 1, height: "100%" }); menuShow(show1, show2); textIntro(info); } }, [state]) return ( <div ref={(el) => (menuWrapper = el)} className="hamburger-menu"> <div ref={(el) => (show1 = el)} className="menu-secondary-background-color" ></div> <div ref={(el) => (show2 = el)} className="menu-layer"> <div className="container"> <div className="wrapper"> <div className="menu-links"> <nav> <ul> <li> <Link ref={(el) => (line1 = el)} to="/about-us" > About </Link> </li> <li> <Link ref={(el) => (line2 = el)} to="/gallery" > Gallery </Link> </li> <li> <Link ref={(el) => (line3 = el)} to="/contact-us" > Contact us </Link> </li> </ul> </nav> <div ref={(el) => (info = el)} className="info"> <h3>Our Vision</h3> <p> Lorem ipsum dolor sit amet consectetur adipisicing elit.... </p> </div> </div> </div> </div> </div> </div> ); } export default Menu

สิ่งที่เราทำในองค์ประกอบ Menu คือการนำเข้าฟังก์ชันภาพเคลื่อนไหว ได้แก่ menuShow , menuHide และ textIntro ต่อไป เรากำหนดตัวแปรสำหรับแต่ละ refs ที่สร้างขึ้นสำหรับองค์ประกอบ DOM ของเราโดยใช้ useRef hook และส่ง null เป็นค่าของพวกมัน ภายในเบ็ด useEffect เราตรวจสอบสถานะของ menu หากการ clicked เป็น false เราจะเรียกฟังก์ชัน menuHide มิฉะนั้น หากสถานะที่ clicked เป็นจริง เราจะเรียกฟังก์ชัน menuShow สุดท้าย เราตรวจสอบให้แน่ใจว่าองค์ประกอบ DOM ที่เกี่ยวข้องถูกส่งผ่านการ refs เฉพาะซึ่งก็คือ menuWrapper , show1 , show2 ด้วยเหตุนี้ เราจึงมีเมนูเคลื่อนไหว

เรามาดูกันว่ามันมีลักษณะอย่างไร

เมนูเคลื่อนไหว
เมนูเคลื่อนไหว

แอนิเมชั่นสุดท้ายที่เราจะปรับใช้คือทำให้รูปภาพของเราในแกลเลอรีของเรา skew เมื่อเลื่อน มาดูสถานะของแกลลอรี่ของเราตอนนี้กัน

แกลลอรี่ที่ไม่มีแอนิเมชั่น
แกลลอรี่ที่ไม่มีแอนิเมชั่น

ในการใช้แอนิเมชั่นเอียงในแกลเลอรีของเรา ไปที่ Animate.js และเพิ่มโค้ดบางส่วนเข้าไป

 .... //Skew gallery Images export const skewGallery = elem1 => { //register ScrollTrigger gsap.registerPlugin(ScrollTrigger); // make the right edge "stick" to the scroll bar. force3D: true improves performance gsap.set(elem1, { transformOrigin: "right center", force3D: true }); let clamp = gsap.utils.clamp(-20, 20) // don't let the skew go beyond 20 degrees. ScrollTrigger.create({ trigger: elem1, onUpdate: (self) => { const velocity = clamp(Math.round(self.getVelocity() / 300)); gsap.to(elem1, { skew: 0, skewY: velocity, ease: "power3", duration: 0.8, }); }, }); }

เราได้สร้างฟังก์ชันที่เรียกว่า skewGallery ผ่าน elem1 เป็นพารามิเตอร์ และลงทะเบียน ScrollTrigger

ScrollTrigger เป็นปลั๊กอินใน GSAP ที่ช่วยให้เราสามารถทริกเกอร์แอนิเมชั่นแบบเลื่อนได้ เช่นเดียวกับกรณีของการเอียงภาพในขณะที่หน้าเลื่อน

ในการทำให้ขอบด้านขวาติดกับแถบเลื่อน เราได้ส่งค่า right center ไปยังคุณสมบัติ transformOrigin เรายังตั้งค่าคุณสมบัติ force3D เป็น true ในส่วนอื่นๆ เพื่อปรับปรุงประสิทธิภาพ

เราประกาศตัวแปร clamp ที่คำนวณความเบ้ของเราและรับรองว่าจะไม่เกิน 20degs ภายในวัตถุ ScrollTrigger เรากำหนดคุณสมบัติ trigger ให้กับพารามิเตอร์ elem1 ซึ่งจะเป็นองค์ประกอบที่ต้องทริกเกอร์เมื่อเราเรียกใช้ฟังก์ชันนี้ เรามีฟังก์ชันเรียกกลับ onUpdate ข้างในเป็นตัวแปร velocity ที่คำนวณความเร็วปัจจุบันและหารด้วย 300

สุดท้าย เราทำให้องค์ประกอบเคลื่อนไหวจากค่าปัจจุบันโดยการตั้งค่าอื่นๆ เราตั้งค่าความ skew เป็น 0 และ skewY เป็นตัวแปร velocity ที่ 0.8

ต่อไป เราต้องเรียกใช้ฟังก์ชันนี้ในไฟล์ App.js ของเรา

 .... import { skewGallery } from "./components/Animate" function Gallery() { let skewImage = useRef(null); useEffect(() => { skewGallery(skewImage) }, []); return ( <div ref={(el) => (skewImage = el)}> <Image/> </div> ) } ....

ที่นี่ เรานำเข้า skewGalley จาก ./components/Animate สร้างการอ้างอิง skewImage ที่กำหนดเป้าหมายองค์ประกอบรูปภาพ ภายใน useEffect hook เราเรียกฟังก์ชัน skewGallery และส่งผ่าน skewImage ref เป็นพารามิเตอร์ สุดท้ายนี้ เราได้ส่ง skewImage ไปที่ ref to attribute

คุณจะเห็นด้วยกับฉันมันเป็นการเดินทางที่เจ๋งมากป่านนี้ นี่คือตัวอย่างใน CodeSanbox

repo ที่สนับสนุนสำหรับบทความนี้มีอยู่ใน Github

บทสรุป

เราได้สำรวจศักยภาพของ GSAP ในโปรเจ็กต์ React แล้ว เราแค่ขีดข่วนพื้นผิวในบทความนี้ ไม่มีการจำกัดสิ่งที่คุณสามารถทำได้ด้วย GSAP เนื่องจากเกี่ยวข้องกับแอนิเมชัน เว็บไซต์อย่างเป็นทางการของ GSAP มีเคล็ดลับเพิ่มเติมเพื่อช่วยให้คุณเข้าใจวิธีการและปลั๊กอินอย่างละเอียด มีการสาธิตมากมายที่จะทำให้คุณทึ่งกับสิ่งที่ผู้คนทำกับ GSAP ฉันชอบที่จะได้ยินประสบการณ์ของคุณกับ GSAP ในส่วนความคิดเห็น

ทรัพยากร

  1. เอกสาร GSAP, GreenSock
  2. “คู่มือสำหรับผู้เริ่มต้นสู่แพลตฟอร์มแอนิเมชั่น GreenSock” Nicholas Kramer, freeCodeCamp
  3. “บทนำสู่แอนิเมชั่นด้วย Greensock Animation API (GSAP)” Zell Liew