ส่วนประกอบปฏิกิริยาเคลื่อนไหวด้วย GreenSock
เผยแพร่แล้ว: 2022-03-10ในช่วงแรกๆ ของเวิลด์ไวด์เว็บ สิ่งต่างๆ ค่อนข้างนิ่งและน่าเบื่อ หน้าเว็บส่วนใหญ่ใช้การออกแบบกราฟิกและเลย์เอาต์จากโลกแห่งการพิมพ์จนกระทั่งมีการแนะนำแอนิเมชั่น แอนิเมชั่นสามารถดึงดูดและดึงความสนใจของผู้คนได้นานกว่าหน้าเว็บแบบคงที่ และสื่อสารแนวคิดหรือแนวคิดได้อย่างชัดเจนและมีประสิทธิภาพมากขึ้น
อย่างไรก็ตาม เมื่อทำไม่ถูกต้อง แอนิเมชั่นอาจขัดขวางการโต้ตอบของผู้ใช้กับผลิตภัณฑ์ของคุณและส่งผลเสียต่อการดึง 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)
มาดูกันว่าไวยากรณ์นี้หมายถึงอะไร
-
method
หมายถึงวิธี GSAP ที่คุณต้องการใช้ -
element
คือองค์ประกอบที่คุณต้องการทำให้เคลื่อนไหว หากคุณต้องการสร้าง tweens สำหรับองค์ประกอบหลายรายการพร้อมกัน คุณสามารถส่งผ่านอาร์เรย์ขององค์ประกอบไปยังelement
-
duration
คือระยะเวลาของทวีตของคุณ เป็นจำนวนเต็มในหน่วยs
(ไม่มีส่วนต่อท้าย!) -
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 มิลลิวินาที
หมายเหตุ : แกน 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.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 ด้านล่าง
หมายเหตุ : เมื่อใดก็ตามที่เราสร้างภาพเคลื่อนไหวคุณสมบัติตำแหน่ง เช่น left
และ top
เราต้องแน่ใจว่าองค์ประกอบที่เกี่ยวข้องจะต้องมีคุณสมบัติตำแหน่ง CSS ของ relative
, absolute
หรือ fixed
ผ่อนปรน
เอกสารอย่างเป็นทางการของ GSAP กำหนดว่าการค่อยๆ เปลี่ยนเป็นวิธีหลักในการเปลี่ยนระยะเวลาของ Tweens ของคุณ กำหนดว่าวัตถุเปลี่ยนตำแหน่งอย่างไรในจุดต่างๆ ความง่ายควบคุมอัตราการเปลี่ยนแปลงของแอนิเมชันใน GSAP และใช้เพื่อกำหนดรูปแบบของแอนิเมชั่นของออบเจ็กต์
GSAP มอบความง่ายดายและตัวเลือกประเภทต่างๆ เพื่อให้คุณควบคุมลักษณะการทำงานของแอนิเมชั่นได้มากขึ้น นอกจากนี้ยังมี Ease Visualizer เพื่อช่วยคุณเลือกการตั้งค่าความง่ายที่คุณต้องการ
ความง่ายมีอยู่สามประเภทและแตกต่างกันไปในการใช้งาน
-
in()
— การเคลื่อนไหวเริ่มอย่างช้าๆ แล้วเร่งความเร็วไปยังจุดสิ้นสุดของแอนิเมชั่น -
out()
— แอนิเมชั่นเริ่มต้นอย่างรวดเร็วแล้วช้าลงเมื่อสิ้นสุดแอนิเมชั่น -
inOut()
— แอนิเมชั่นเริ่มช้า เร่งความเร็วครึ่งทาง และสิ้นสุดอย่างช้าๆ
ในตัวอย่างการค่อยๆ เปลี่ยนเหล่านี้ เราเชื่อมโยง 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 ด้านล่าง
ตอนนี้เราเข้าใจองค์ประกอบพื้นฐานของ 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 ในส่วนความคิดเห็น
ทรัพยากร
- เอกสาร GSAP, GreenSock
- “คู่มือสำหรับผู้เริ่มต้นสู่แพลตฟอร์มแอนิเมชั่น GreenSock” Nicholas Kramer, freeCodeCamp
- “บทนำสู่แอนิเมชั่นด้วย Greensock Animation API (GSAP)” Zell Liew