نحوه ساخت یک کامپوننت سوایپ موبایل در React
این روزها همه دوست دارند که بتوانند از طریق تلفن همراه خود به وب دسترسی داشته باشند. پس مهم است که دسترسی به برنامه وب خود را در اندروید و آیفون در نظر بگیرید.
سختترین بخش ساخت ناوبری است – و بهویژه کشیدن انگشت میتواند باعث سردردهای زیادی شود. کتابخانههایی وجود دارد که میتوانید از آنها برای کمک به این موضوع استفاده کنید، اما چرا خودتان آن را ایجاد نکنید؟
در این آموزش به شما یاد می دهم که چگونه در React کامپوننت کشیدن موبایل خود را بسازید. می توانید آن را در 50 خط جاوا اسکریپت انجام دهید.
در ابتدا، من این کامپوننت را برای پروژه حیوان خانگی خود، بازی 2048 در React ایجاد کردم و اکنون تصمیم گرفتم نحوه انجام آن را به اشتراک بگذارم.
اگر میخواهید قبل از خواندن کل مقاله آن را امتحان کنید، میتوانید بازی را در اینجا انجام دهید (از دستگاه تلفن همراه خود استفاده کنید). در این آموزش، ما فقط بر روی کشیدن گوشی موبایل تمرکز خواهیم کرد.
می توانید منابع زیر را در GitHub بیابید:
در اینجا اوج پنهانی است (کیفیت بهترین نیست زیرا سعی می کردم اندازه را کوچک نگه دارم):
فهرست مطالب:
چگونه یک دستگاه موبایل را در مرورگر خود شبیه سازی کنیم
🛠️ پیش نیازهای P
قبل از شروع، مطمئن شوید که کمی در مورد React و جاوا اسکریپت می دانید. شما به هیچ ابزار پیچیده ای نیاز ندارید، اما اگر می خواهید نمونه پروژه را روی رایانه خود اجرا کنید، ابتدا باید Node.js را نصب کنید.
همچنین، من از Google Chrome برای شبیه سازی یک دستگاه تلفن همراه در رایانه خود استفاده می کنم. به خاطر داشته باشید که اگر از مرورگر دیگری استفاده می کنید، ممکن است مراحل کمی متفاوت باشد.
🔍 چگونه یک دستگاه موبایل را در مرورگر خود شبیه سازی کنیم
قبل از شروع کدنویسی، باید به شما نشان دهم که چگونه یک دستگاه تلفن همراه را در Google Chrome شبیه سازی کنید.
مرورگر خود را باز کنید، روی صفحه خود کلیک راست کرده و از منوی کشویی " Inspect " را انتخاب کنید.
نمای مرورگر شما اکنون باید به دو قسمت تقسیم شود. بخش دوم شامل ابزارهای توسعه دهنده کروم است.
اکنون روی نماد "لپ تاپ و موبایل" (1 در تصویر زیر) در گوشه سمت چپ بالای ابزار Developer کلیک کنید. سپس "Dimensions" (2) دستگاهی را که می خواهید شبیه سازی کنید انتخاب کنید. من آیفون SE را انتخاب کردم زیرا این دستگاه دارای کمترین وضوح پشتیبانی شده توسط بازی من است.
اکنون ما آماده ایم تا با استفاده از موس یا پد لمسی، کشیدن کشیدن انگشت را شبیه سازی کنیم. فقط به GIF زیر توجه کنید - مکان نما من به یک دایره تبدیل شده است که قرار است ناحیه پوشانده شده توسط انگشت شخص را تجسم کند.
وقتی میخواهم تند بکشم، مرورگرم فکر میکند که در واقع در وبسایت پیمایش میکنم. در مورد من، این یک رفتار مورد انتظار نیست. من می خواهم به جای آن از کشیدن انگشت برای انجام بازی استفاده کنم.
🤓 جزء MobileSwiper
ابتدا باید یک swiper برای موبایل ایجاد کنیم . فایل jsx در این فایل یک کامپوننت استاندارد React را اعلام می کنیم. مؤلفه ما باید دو ویژگی را بپذیرد - children
و onSwipe
.
export default function MobileSwiper({ children, onSwipe }) { return null }
بگذارید به طور مختصر در مورد آنها توضیح دهم:
children
به MobileSwiper
اجازه میدهد تا هر محتوایی را که بین تگهای باز و بسته شدن آن قرار میگیرد، بپذیرد و ارائه دهد. این به شما امکان می دهد کل برد را در داخل این جزء تزریق کنید - اما بعداً به این موضوع خواهیم رسید.
onSwipe
یک تماس برگشتی است که هر بار که کاربر در ناحیه «قابل کشیدن» تند بکشد، مؤلفه ما فعال میشود.
بیایید اکنون منطقه قابل کشیدن را تعریف کنیم. ابتدا باید یک مرجع به عنصر DOM اضافه کنید که میخواهید در آن اجازه بکشید. با استفاده از قلاب useRef
می توانید این کار را انجام دهید. پس یک ثابت به نام wrapperRef
را اعلام کنید:
import { useRef } from "react" export default function MobileSwiper({ children, onSwipe }) { const wrapperRef = useRef(null) return null }
نکته جانبی: useRef
یک React Hook است که به شما امکان میدهد به مقداری اشاره کنید که برای رندر کردن لازم نیست. استفاده از آن برای دستکاری DOM بسیار رایج است. React پشتیبانی داخلی برای این دارد.
اکنون فقط باید <div />
را برگردانید که به ثابتی که با استفاده از قلاب useRef
ایجاد کرده اید ارجاع می دهد.
import { useRef } from "react" export default function MobileSwiper({ children, onSwipe }) { const wrapperRef = useRef(null) return <div ref={wrapperRef}>{children}</div> }
بیایید یک لحظه فکر کنیم که چگونه می توانیم کشیدن انگشت را تشخیص دهیم. من معتقدم ساده ترین راه مقایسه موقعیت شروع و پایان انگشت کاربر است.
این بدان معناست که باید موقعیت اولیه انگشت کاربر را در حالت ذخیره کنیم. اساسا، ما مختصات x
و y
را با استفاده از قلاب useState
ذخیره می کنیم.
import { useState, useRef } from "react" export default function MobileSwiper({ children, onSwipe }) { const wrapperRef = useRef(null) const [startX, setStartX] = useState(0) const [startY, setStartY] = useState(0) return <div ref={wrapperRef}>{children}</div> }
اکنون باید دو تماس رویداد ایجاد کنیم:
handleTouchStart
موقعیت شروع انگشت کاربر را تنظیم می کند.
handleTouchEnd
موقعیت نهایی انگشت کاربر را تنظیم می کند و شیفت (مثلث) را بر اساس نقطه شروع محاسبه می کند.
بیایید با کنترل کننده رویداد handleTouchStart
شروع کنیم:
import { useCallback, useState, useRef } from "react" export default function MobileSwiper({ children, onSwipe }) { const wrapperRef = useRef(null) const [startX, setStartX] = useState(0) const [startY, setStartY] = useState(0) const handleTouchStart = useCallback((e) => { if (!wrapperRef.current.contains(e.target)) { return } e.preventDefault() setStartX(e.touches[0].clientX) setStartY(e.touches[0].clientY) }, []) return <div ref={wrapperRef}>{children}</div> }
اجازه دهید به طور خلاصه توضیح دهم:
من این راهنما را در قلاب useCallback
قرار دادم تا عملکرد آن را در حافظه پنهان ذخیره کنم و بهبود بخشم. اگر این قلاب را نمیشناسید، میتوانید در اسناد رسمی React درباره آن بخوانید.
دستور if
تحلیل می کند که آیا کاربر در حال کشیدن انگشت در ناحیه قابل کشیدن است یا خیر. اگر آنها به خارج از این ناحیه بکشند، ما به اسکرول کردن ادامه خواهیم داد.
e.preventDefault()
رویداد پیمایش پیشفرض را غیرفعال میکند.
دو خط آخر مختصات x
و y
را در حالت ذخیره می کنند.
حال اجازه دهید کنترل کننده رویداد handleTouchEnd
را پیاده سازی کنیم:
import { useCallback, useState, useRef } from "react" export default function MobileSwiper({ children, onSwipe }) { const wrapperRef = useRef(null) const [startX, setStartX] = useState(0) const [startY, setStartY] = useState(0) const handleTouchStart = useCallback((e) => { if (!wrapperRef.current.contains(e.target)) { return } e.preventDefault() setStartX(e.touches[0].clientX) setStartY(e.touches[0].clientY) }, []) const handleTouchEnd = useCallback((e) => { if (!wrapperRef.current.contains(e.target)) { return } e.preventDefault() const endX = e.changedTouches[0].clientX const endY = e.changedTouches[0].clientY const deltaX = endX - startX const deltaY = endY - startY onSwipe({ deltaX, deltaY }) }, [startX, startY, onSwipe]) return <div ref={wrapperRef}>{children}</div> }
همانطور که می بینید، مراحل 1-3 دقیقاً مشابه پاسخ تماس handleTouchStart
است. اکنون مختصات x
و y
نهایی انگشت کاربر را می گیریم و x
و y
اولیه را از آن کسر می کنیم. به لطف آن می توانیم جابجایی افقی و عمودی انگشت کاربر (دلتا) را محاسبه کنیم.
سپس آن دلتاها را بر روی onSwipe
callback ارسال می کنیم. اگر به خاطر داشته باشید، در ابتدا آن را در قطعات کامپوننت اعلام کردیم.
اکنون باید آن تماس ها را به شنونده رویداد متصل کنیم. برای انجام این کار، می توانیم از قلاب useEffect
از React استفاده کنیم.
import { useCallback, useEffect, useState, useRef } from "react" export default function MobileSwiper({ children, onSwipe }) { const wrapperRef = useRef(null) const [startX, setStartX] = useState(0) const [startY, setStartY] = useState(0) const handleTouchStart = useCallback((e) => { if (!wrapperRef.current.contains(e.target)) { return } e.preventDefault() setStartX(e.touches[0].clientX) setStartY(e.touches[0].clientY) }, []) const handleTouchEnd = useCallback( (e) => { if (!wrapperRef.current.contains(e.target)) { return } e.preventDefault() const endX = e.changedTouches[0].clientX const endY = e.changedTouches[0].clientY const deltaX = endX - startX const deltaY = endY - startY onSwipe({ deltaX, deltaY }) }, [startX, startY, onSwipe]) useEffect(() => { window.addEventListener("touchstart", handleTouchStart) window.addEventListener("touchend", handleTouchEnd) return () => { window.removeEventListener("touchstart", handleTouchStart) window.removeEventListener("touchend", handleTouchEnd) } }, [handleTouchStart, handleTouchEnd]) return <div ref={wrapperRef}>{children}</div> }
می توانید اطلاعات بیشتری در مورد قلاب useEffect
در اسناد رسمی React بخوانید.
مؤلفه MobileSwiper اکنون آماده است.
🔌 بیایید آن را قابل کشیدن کنیم
آخرین کاری که باید انجام دهیم این است که جزء خود را به برنامه متصل کنیم. همانطور که اشاره کردم، من از این مؤلفه در بازی 2048 خود استفاده خواهم کرد ( کد منبع ). اگر میخواهید از آن در جای دیگری استفاده کنید، راهنمای handleSwipe
و مؤلفه MobileSwiper یکسان باقی میمانند.
بیایید آن را به مؤلفه Board وصل کنیم:
import { useCallback, useContext, useEffect, useRef } from "react" import { Tile as TileModel } from "@/models/tile" import styles from "@/styles/board.module.css" import Tile from "./tile" import { GameContext } from "@/context/game-context" import MobileSwiper from "./mobile-swiper" export default function Board() { const { getTiles, moveTiles, startGame } = useContext(GameContext); // ... removed irrelevant parts ... const handleSwipe = useCallback(({ deltaX, deltaY }) => { if (Math.abs(deltaX) > Math.abs(deltaY)) { if (deltaX > 0) { moveTiles("move_right") } else { moveTiles("move_left") } } else { if (deltaY > 0) { moveTiles("move_down") } else { moveTiles("move_up") } } }, [moveTiles]) // ... removed irrelevant parts ... return ( <MobileSwiper onSwipe={handleSwipe}> <div className={styles.board}> <div className={styles.tiles}>{renderTiles()}</div> <div className={styles.grid}>{renderGrid()}</div> </div> </MobileSwiper> ) }
بیایید با handleSwipe
handler شروع کنیم. همانطور که می بینید، ما در حال مقایسه هستیم که آیا deltaX
بزرگتر از deltaY
است تا تصمیم بگیریم که آیا کاربر به صورت افقی (چپ / راست) یا عمودی (بالا / پایین) حرکت کرده است.
اگر تند کشیدن افقی بود، پس:
منفی deltaX
به این معنی است که آنها به سمت چپ کشیدند.
deltaX
مثبت به این معنی است که آنها به سمت راست حرکت کردند.
اگر تند کشیدن عمودی بود، پس:
منفی deltaY
به این معنی است که آنها به سمت بالا سوایپ کردند.
deltaY
مثبت به این معنی است که آنها به سمت پایین سوایپ کردند.
اکنون، بیایید روی مولفه MobileSwiper تمرکز کنیم. می توانید آن را در بیانیه return
پیدا کنید. ما کمک کننده handleSwipe
را به ویژگی onSwipe
میدهیم و کل کد HTML مؤلفه Board را میپیچانیم تا کشیدن روی آن فعال شود.
حالا وقتی آن را امتحان می کنیم، نتیجه ایده آل نیست. همانطور که در زیر می بینید، رویدادهای پیمایش با تند کشیدن تلفن همراه ترکیب می شوند:
این به این دلیل اتفاق می افتد که مرورگرهای مدرن از شنوندگان رویداد غیرفعال برای بهبود تجربه اسکرول در دستگاه های تلفن همراه استفاده می کنند. این بدان معناست که preventDefault
که به تماسهای رویداد خود اضافه کردهایم هرگز اتفاق نمیافتد.
برای غیرفعال کردن رفتار پیمایش، باید شنوندگان غیرفعال را در مؤلفه MobileSwiper غیرفعال کنیم:
import { useCallback, useEffect, useState, useRef } from "react" export default function MobileSwiper({ children, onSwipe }) { // ... removed to improve visibility ... useEffect(() => { window.addEventListener("touchstart", handleTouchStart, { passive: false }) window.addEventListener("touchend", handleTouchEnd, { passive: false }) // ... removed to improve visibility ... }, [handleTouchStart, handleTouchEnd]) // ... removed to improve visibility ... }
اکنون رفتار اسکرول از بین رفته است و بازی 2048 بسیار عالی به نظر می رسد:
🏁 خلاصه
امروز به شما نشان دادم که برای مدیریت حرکات موبایل در React همیشه به کتابخانه نیاز ندارید. برخی از رویدادهای ساده مانند کشیدن انگشت را می توان با استفاده از ویژگی های اولیه React پیاده سازی کرد. ما فقط از یک دسته قلاب React استفاده کردیم و دو کنترل کننده رویداد ساده نوشتیم.
کل پیاده سازی دقیقاً 50 خط کد دارد. امیدوارم به شما انگیزه داده باشم که سعی کنید به تنهایی با رویدادهای تلفن همراه مقابله کنید.
اگر این مقاله به شما کمک کرد، لطفاً در توییتر به من اطلاع دهید . مربیانی مثل من اغلب احساس میکنند که ما در خلأ صحبت میکنیم و هیچکس به آنچه آموزش میدهیم اهمیتی نمیدهد. یک «فریاد» ساده نشان میدهد که ارزش تلاش را داشت و به من انگیزه میدهد تا محتوای بیشتری از این دست ایجاد کنم.
لطفا این مقاله را در شبکه های اجتماعی خود به اشتراک بگذارید. متشکرم!
🎥 بازی 2048 خود را بسازید
این مقاله بخشی از دوره آموزشی من در Udemy است که در آن نحوه ایجاد یک بازی کاملاً کاربردی 2048 در Next.js را از ابتدا آموزش میدهم.
🧑🎓 به دوره Next.js من در Udemy بپیوندید
برای ثبت نام از کد FREECODECAMP استفاده کنید تا 60 درصد تخفیف دریافت کنید.
من معتقدم برنامه نویسی باید سرگرم کننده باشد و خلاقیت را آزاد کند. شما مجبور نیستید فهرست TODO دیگری یا یک سبد خرید بسازید. در عوض، میتوانید چیزی بسازید که بتوانید به دوستانتان یا شاید حتی یک مدیر استخدام نشان دهید!
PS. اگر ترجیح می دهید فیلم های صفحه نمایش را تماشا کنید، پس این درس به صورت رایگان در Udemy در دسترس است. میتوانید آن را در بخش « طرحبندی پاسخگو و ویژگی بازی از دست رفته » در سخنرانی به نام « طرحبندی بازی و تند کشیدنهای موبایل » پیدا کنید.
ارسال نظر