การเปลี่ยนหน้าหน้าง่ายและปรับแต่งได้สำหรับแอพ next.js
ตัวอย่าง: https://next-page-transitions.now.sh/
พูดง่ายๆก็คือการเพิ่มการเปลี่ยนหน้าเว็บเป็นแอพสร้างด้วย next.js มันอาจใช้งานได้กับเฟรมเวิร์กอื่น ๆ แต่มันถูกออกแบบมารอบ ๆ องค์ประกอบ App ใหม่และวิธีที่ Next.js จัดการหน้า โดยเฉพาะอย่างยิ่งมันแก้ปัญหาของการตรวจสอบให้แน่ใจว่ามีการติดตั้งส่วนประกอบหน้าเดียวในแต่ละครั้งและไม่ได้ติดตั้งหน้าถัดไปจนกว่าจะมีการติดตั้งหน้าจอแอนิเมชั่นทางออกก่อนหน้านี้ นอกจากนี้ยังมีการสนับสนุนในตัวสำหรับการแสดงตัวบ่งชี้การโหลดหากส่วนประกอบหน้าของคุณต้องโหลดข้อมูลก่อนที่จะสามารถแสดงได้
หากคุณต้องการเรียนรู้จากตัวอย่างให้ตรวจสอบไดเรกทอรี examples สำหรับแอพ Next.js บางตัวที่แสดงให้เห็นว่าสามารถใช้ไลบรารีนี้ได้อย่างไร
ก่อนอื่นติดตั้งแพ็คเกจ:
npm install --save next-page-transitions
ถัดไปตรวจสอบให้แน่ใจว่าแอปของคุณมีส่วนประกอบ App ที่กำหนดเอง ถ้าไม่ทำตามตัวอย่างใน next.js readme เพื่อสร้าง จากนั้นในวิธีการเรนเดอร์ของ App ของคุณให้ห่อ Component หน้าในส่วนประกอบของ PageTransition คุณจะต้องกำหนดคลาส CSS ของคุณเองที่บรรลุภาพเคลื่อนไหวการเปลี่ยนแปลงที่คุณต้องการ เพื่อให้ห้องสมุดนี้เรียบง่ายและอธิบายถึงวิธีการที่หลากหลายที่ผู้คนผลิตและบริโภค CSS มันไม่ได้มีสไตล์ในตัวและไม่มีความเห็นเป็นพิเศษเกี่ยวกับวิธีการที่สไตล์ของคุณ ตัวอย่างด้านล่างมีการเปลี่ยนแปลงอย่างง่ายที่จางหายไปหน้าเข้าและออก
import App , { Container } from 'next/app'
import React from 'react'
import { PageTransition } from 'next-page-transitions'
export default class MyApp extends App {
static async getInitialProps ( { Component , router , ctx } ) {
let pageProps = { }
if ( Component . getInitialProps ) {
pageProps = await Component . getInitialProps ( ctx )
}
return { pageProps }
}
render ( ) {
const { Component , pageProps , router } = this . props
return (
< Container >
< PageTransition timeout = { 300 } classNames = "page-transition" >
< Component { ... pageProps } key = { router . route } />
</ PageTransition >
< style jsx global > { `
.page-transition-enter {
opacity: 0;
}
.page-transition-enter-active {
opacity: 1;
transition: opacity 300ms;
}
.page-transition-exit {
opacity: 1;
}
.page-transition-exit-active {
opacity: 0;
transition: opacity 300ms;
}
` } </ style >
</ Container >
)
}
} เมื่อคุณย้ายไปยังหน้าใหม่เสา key จะเปลี่ยนไปและส่วนประกอบของ PageTransition จะตรวจจับสิ่งนั้น แทนที่จะปลดหน้าเว็บทันทีมันจะใช้คลาส page-transition-exit กับ wrapper รอบหน้าเพื่อเริ่มต้นการเปลี่ยนแปลง "ออก" จากนั้นจะใช้คลาส page-transition-exit-active เพื่อเริ่มการเปลี่ยนแปลง สิ่งนี้คล้ายกันมากกับวิธีที่ห้องสมุด React-Transition-Group ทำสิ่งต่าง ๆ หลังจากหน้าก่อนหน้าได้รับการเคลื่อนไหวหน้าใหม่จะถูกติดตั้งและคู่ที่คล้ายกันของ .page-transition-enter และ page-transition-enter-active จะถูกนำไปใช้ กระบวนการนี้จะทำซ้ำทุกครั้งที่หน้าใหม่ถูกนำทางไป
หมายเหตุ : ในเวอร์ชันก่อนหน้าของ next-page-transitions ไม่จำเป็นต้องระบุเสา key เกี่ยวกับเด็ก ๆ ของ PageTransition อย่างไรก็ตามเพื่อให้การโหลดโมดูลร้อนทำงานอย่างถูกต้องจำเป็นต้องทำให้เสานี้จำเป็น การเคลื่อนย้าย Foward เด็กที่ไม่ได้ระบุเสา key จะทำให้เกิดคำเตือนในคอนโซล ในอนาคตสิ่งนี้อาจกลายเป็นข้อผิดพลาดรันไทม์
สมมติว่าคุณมีหน้าเว็บที่ต้องทำคำขอเครือข่ายก่อนที่จะสามารถแสดงเนื้อหาได้ คุณสามารถให้หน้าเว็บเองทำให้สปินเนอร์กำลังโหลดได้จนกว่าจะพร้อมที่จะไป แต่จากนั้นคุณก็สูญเสียแอนิเมชั่นการเปลี่ยนเพจที่สวยงามที่คุณใช้ไปตลอดเวลาที่สมบูรณ์แบบ โชคดีที่ห้องสมุดนี้ทำให้ง่ายต่อการจัดการกรณีนั้น
หากคุณเพิ่มคุณสมบัติคงที่ pageTransitionDelayEnter = true ในส่วนประกอบหน้าของคุณหน้าของคุณจะถูกส่งผ่านเสาโทรกลับพิเศษที่คุณสามารถใช้เพื่อระบุว่าทุกอย่างเสร็จสิ้นการโหลดเสร็จ ในระหว่างนี้หน้าของคุณจะถูกติดตั้ง แต่การเปลี่ยนแปลง Enter ยังไม่เริ่มต้นและตัวบ่งชี้การโหลดที่คุณเลือกจะปรากฏในสถานที่ เมื่อคุณเรียกเสาโทรกลับสปินเนอร์กำลังโหลดจะถูกซ่อนและหน้าของคุณจะถูกเคลื่อนไหวเข้าที่! โดยค่าเริ่มต้นการโทรกลับจะถูกส่งผ่าน pageTransitionReadyToEnter Prop แต่สามารถระบุได้โดยการตั้งค่าเสา loadingCallbackName บนส่วนประกอบ PageTransition ของคุณ
หมายเหตุ: ตรวจสอบให้แน่ใจว่าส่วนประกอบของคุณส่งคืนค่า null จากฟังก์ชั่น render() จนกว่าจะเสร็จสิ้นการโหลดเนื้อหาและพร้อมที่จะเคลื่อนไหวหน้าของคุณจะยังคงอยู่ในแผนผังรีเรสต์ในขณะที่กำลังโหลด!
"แต่คำขอเครือข่ายของฉันมักจะเร็ว!" คุณจะพูด "พวกเขามักจะใช้เวลาเพียงไม่กี่ร้อยมิลลิวินาทีและฉันไม่ต้องการแฟลชตัวบ่งชี้การโหลดบนหน้าจอในช่วงเวลาสั้น ๆ !" ห้องสมุดนี้สามารถจัดการกรณีนั้นได้เช่นกัน หากคุณระบุ Prop loadingDelay ตัวบ่งชี้การโหลดจะไม่ปรากฏจนกว่าจะถึงเวลาที่ผ่านไป หากส่วนประกอบของคุณพร้อมที่จะป้อนก่อนหน้านั้นตัวบ่งชี้การโหลดจะไม่ปรากฏขึ้นทำให้ UX สะอาดและเร็ว อย่างไรก็ตามหากส่วนประกอบของคุณใช้เวลานานตัวบ่งชี้การโหลดจะปรากฏขึ้นจนกว่าส่วนประกอบของคุณจะพร้อม
"นั่นฟังดูเป็นแนวคิดของตัวยึดตำแหน่งจากการพูดคุยที่น่าสงสัยว่าในวิดีโอ YouTube นี้" ใช่ใช่แล้ว! นั่นคือแรงบันดาลใจสำหรับคุณสมบัตินี้
นี่คือองค์ประกอบตัวอย่างที่จำลองคำขอเครือข่ายด้วยการหมดเวลา:
class About extends React . Component {
static pageTransitionDelayEnter = true
constructor ( props ) {
super ( props )
this . state = { loaded : false }
}
componentDidMount ( ) {
this . timeoutId = setTimeout ( ( ) => {
this . props . pageTransitionReadyToEnter ( )
this . setState ( { loaded : true } )
} , 2000 )
}
componentWillUnmount ( ) {
if ( this . timeoutId ) clearTimeout ( this . timeoutId )
}
render ( ) {
if ( ! this . state . loaded ) return null
return < div > Hello, world! </ div >
}
} สมมติว่าสักครู่ว่าคุณมีส่วนประกอบ Loader ที่แสดงตัวบ่งชี้การโหลดการหมุนที่ดี คุณจะต้องบอกส่วนประกอบ PageTransition ที่คุณต้องการใช้ส่วนประกอบนี้และระยะเวลาที่คุณต้องการรอจนกว่าจะแสดงตัวบ่งชี้เครือข่าย:
<PageTransition
timeout={300}
classNames="page-transition"
loadingComponent={<Loader />}
loadingDelay={500}
loadingTimeout={{
enter: 400,
exit: 0,
}}
loadingClassNames="loading-indicator"
>
<Component {...pageProps} key={router.route} />
</PageTransition>
คุณจะต้องเพิ่มสไตล์หากคุณต้องการให้ตัวบ่งชี้การโหลดเปิด/ปิดหน้าจอ หากคุณต้องการให้มันปรากฏ/หายไปโดยไม่มีภาพเคลื่อนไหวใด ๆ คุณสามารถเพิ่ม loadingTimeout={0} และละเว้นคุณสมบัติ loadingClassNames
ตรวจสอบแอพ delayed-enter สู่ไดเรกทอรี examples สำหรับตัวอย่างที่สมบูรณ์ของสิ่งนี้ หน้า "เกี่ยวกับ" ( pages/about.js ) จะรอ 2 วินาทีก่อนที่จะแสดงเนื้อหาและในระหว่างนี้ส่วนประกอบที่ components/Loader.js จะปรากฏขึ้น เล่นกับความล่าช้าต่าง ๆ เพื่อให้ได้ความรู้สึกที่ลึกซึ้งยิ่งขึ้นว่าองค์ประกอบนี้ทำงานอย่างไร
PageTransitionclassNames : ระบุชื่อคลาสที่จะนำไปใช้กับ wrapper หน้าเพื่อขับแอนิเมชั่นการเปลี่ยนหน้า คล้ายกับ Prop classNames ขององค์ประกอบ CSSTranstition ของ react-transition-group อย่างไรก็ตามโปรดทราบว่าเฉพาะรูปแบบสตริงของเสานั้นรองรับในปัจจุบัน นอกจากนี้โปรดทราบว่าห้องสมุดนี้ไม่มีสถานะ "ปรากฏ" แยกต่างหาก จำเป็นต้องใช้คลาส "Enter" และ "Exit" เท่านั้นtag : ระบุแท็กหรือส่วนประกอบที่จะใช้ในการแสดงผลห่อหน้า องค์ประกอบนี้จะได้รับ prop classNames สิ่งนี้มีประโยชน์หากคุณต้องการใช้มาร์กอัปความหมายเช่นหากคุณต้องการทำให้หน้ากระดาษเป็น main หรือหากคุณต้องการปรับแต่งสไตล์หรือพฤติกรรมของ wrapper หน้าtimeout : ระบุการหมดเวลาสำหรับภาพเคลื่อนไหวการเปลี่ยนหน้า คล้ายกับเสา timeout ขององค์ประกอบ CSSTranstition ของ react-transition-grouploadingComponent : องค์ประกอบปฏิกิริยาที่จะแสดงในขณะที่loadingDelay : ระยะเวลาที่จะรอก่อนแสดงตัวบ่งชี้การโหลดเป็นมิลลิวินาที หากหน้าเสร็จสิ้นการโหลดก่อนระยะเวลานี้ผ่านไปแล้วส่วนประกอบการโหลดจะไม่ปรากฏขึ้น ค่าเริ่มต้นเป็น 500msloadingCallbackName : ระบุชื่อของเสาที่หน้าของคุณจะได้รับการโทรเมื่อทำการโหลดเสร็จแล้ว ค่าเริ่มต้นเป็น pageTransitionReadyToEnterloadingTimeout : คล้ายกับเสา timeout ของส่วนประกอบ CSSTranstition ของ react-transition-group หากเสานี้ถูกตั้งค่าเป็น 0 ตัวบ่งชี้การโหลดจะไม่เปิด/ปิดหน้าจอloadingClassNames : ระบุชื่อคลาสที่จะนำไปใช้กับส่วนประกอบการโหลดหากมีการระบุ คล้ายกับ Prop classNames ขององค์ประกอบ CSSTranstition ของ react-transition-groupmonkeyPatchScrolling : โดยค่าเริ่มต้นส่วนประกอบ Link ของถัดไปจะเลื่อนไปที่ด้านบนของหน้าเมื่อใดก็ตามที่มีการคลิก สิ่งนี้อาจมีเอฟเฟกต์ที่น่าพึงพอใจเมื่อหน้าเปลี่ยนหน้า หากเสานี้ถูกตั้งค่าเป็น true เมื่อติดตั้งส่วนประกอบแล้ว window.scrollTo จะเป็นลิงที่จับได้เพื่อให้สามารถปิดการเลื่อนแบบเป็นโปรแกรมในขณะที่หน้ากำลังเปลี่ยน ค่าเริ่มต้นเป็นเท็จเนื่องจากพฤติกรรมที่อาจเป็นภาพร่างนี้ควรเลือกเข้าร่วมskipInitialTransition : ระบุว่าการเปลี่ยนหน้าจะถูกละเว้นในการเมาท์ครั้งแรกหรือไม่ หากคุณต้องการมีการเปลี่ยนแปลงระหว่างหน้าเท่านั้นไม่ใช่ในการโหลดหน้าแรกให้ตั้งค่า skipInitialTransition เป็น true โดยค่าเริ่มต้น skipInitialTransition จะถูกตั้งค่าเป็น falseยินดีต้อนรับ PRS! ก่อนที่จะทำงานและส่ง PR โปรดสร้างปัญหาที่อธิบายคุณสมบัติที่คุณต้องการสร้าง มันอาจจะอยู่นอกขอบเขตของโครงการนี้หรือผู้ดูแลอาจกำลังทำงานอยู่แล้ว