پیاده سازی حالت تیره در اپلیکیشن ری اکت — به زبان ساده

۲۷۱ بازدید
آخرین به‌روزرسانی: ۱۴ شهریور ۱۴۰۲
زمان مطالعه: ۶ دقیقه
پیاده سازی حالت تیره در اپلیکیشن ری اکت — به زبان ساده

امروزه اغلب اپلیکیشن‌ها از یک «حالت تیره» (Dark Mode) استفاده می‌کنند تا کاربر بتواند بین استفاده از قالب روشن و تیره انتخاب بکند. حالت تیره در طراحی اپلیکیشن‌ها و نرم‌افزارها رواج فراوانی یافته است. علاوه بر این که «حالت تیره» خود قابلیت جالبی است، می‌تواند به کاهش مصرف توان دستگاه و همچنین به کاهش فشار بر چشم کاربر نیز کمک کند. در این مقاله با روش پیاده سازی حالت تیره در اپلیکیشن ری اکت آشنا می‌شویم.

997696

پیاده سازی حالت تیره در اپلیکیشن ری اکت

اپلیکیشنی که در این راهنما مورد بررسی قرار می‌دهیم کدهای CSS فراوانی دارد، اما برای حفظ انسجام صرفاً CSS مرتبط با کارکرد حالت شب/روز را ارائه می‌کنیم. ابتدا باید کمی با چارچوب مسئله آشنا شویم. اپلیکیشن ری‌اکت مورد بررسی یک ادیتور متن آنلاین است. کامپوننت App پس‌زمینه سفیدی دارد و رنگ نوشته‌ها نیز سیاه است. این قالب رنگی در سراسر اپلیکیشن رعایت شده است.

کد کامپوننت App به صورت زیر است:

1import React, {Component} from 'react';
2import './App.css';
3import SizeContainer from './components/SizeContainer.js';
4import {withRouter} from 'react-router-dom';
5import { connect } from 'react-redux'; 
6const App = (props) => {     
7   return (      
8      <div className={!props.mode ? "App" : 'night'}>        
9         <h1 style={{height: 50, marginBottom: 0, padding: 5}}>
10           React Editor
11         </h1>        
12         <SizeContainer mode={props.mode}/>      
13      </div>    
14   );
15} 
16const mapStateToProps = (state) => {  
17   return {      
18      mode: state.mode  
19   };
20} 
21export default withRouter(connect(mapStateToProps) (App));

چنان که می‌بینید، کامپوننت App از طریق mapStateToProps به یک prop به نام mode دسترسی دارد. آن را با connect اکسپورت می‌کنیم. با این که استفاده از ریداکس برای این کارکرد ضرورتی ندارد، اما موجب می‌شود که اعمال استایل‌ها آسان‌تر شود و کامپوننت‌ها مدیریت بهتری می‌یابند. کد reducer به صورت زیر است:

1export default function rootReducer(state={mode: false}, action){
2   switch(action.type){      
3      case "CHANGE_MODE":      
4         var mode = !state.mode        
5         return {...state, mode}      
6      default:        
7         return state    
8    }   
9}

زمانی که CHANGE_MODE فراخوانی می‌شود، تنها کاری که باید انجام شود، دریافت مقدار mode در حالت reducer و انتساب آن به مقدار مخالف (true/false) کنونی است.

اگر state.mode به صورت true باشد، !state.mode برابر با false خواهد بود و برعکس. در عمل به هیچ payload نیاز نداریم. اکنون با شیوه مدیریت reducer آشنا شدیم، زمان آن رسیده که به بررسی عملی CHANGE_MODE در فایل خود بپردازیم.

1export function changeMode(){  
2   return {    
3      type: "CHANGE_MODE"  
4   }
5}

از آنجا که هیچ payload وجود ندارد و عملیات toggle در reducer رخ می‌دهد، تنها کاری که برای تغییر دادن قالب باید انجام دهیم، فراخوانی این تابع در یکی از کامپوننت‌ها است. بدین ترتیب به کامپوننت جدیدی به نام SizeContainer نیاز داریم.

از آنجا که props.mode را از App به SizeContainer می‌فرستیم، عناصر فرزند در SizeContainer نیز به props.mode دسترسی خواهند داشت. این وضعیت به طور خاص برای کامپوننت فرزندی به نام Buttons اهمیت دارد:

1import React from 'react';
2import {FaFileCode, FaLightbulb} from "react-icons/fa";
3import {withRouter} from 'react-router-dom';
4import { connect } from 'react-redux';
5import { changeMode } from './../actions'
6const Buttons  = (props) => {
7    var {mode, changeMode} = props;
8    return(
9      <div className='buttonsContainer' >
10         <div>
11           <div className='buttons' onClick={changeMode}>
12              <FaLightbulb/>
13              <span className="tooltiptext">
14                 {mode ? "Day Mode" : "Night Mode"}
15              </span>
16            </div>
17            <div className='buttons'>
18               <FaFileCode/>
19               <span className="tooltiptext">
20                   Download Code
21                </span>
22            </div>
23          </div>
24       </div>
25    )
26};
27export default withRouter(connect(null, {changeMode}) (Buttons))

کد فوق دو دکمه زیر را رندر می‌کند که یکی آیکون لامپ و دیگری آیکون فایل کد است.

حالت تیره در اپلیکیشن ری اکت

چنان که احتمالاً حدس می‌زنید، دکمه آیکون لامپ حالت تیره را کنترل می‌کند. در مورد دکمه دوم فعلاً چیزی نمی‌گوییم. به خط کد زیر توجه کنید:

1import { changeMode } from './../actions'

این تابع changeMode است که از actions اکسپورت می‌شود. این تابع دکمه آیکون لامپ را به صورت یک رویداد onClick اضافه می‌کند. روی دکمه کلیک کنید تا اکشن تغییر حالت اجرا شود.

tool tip دکمه لامپ، در صورتی که props.mode برابر با true باشد، عبارت Day Mode را نشان می‌دهد که معنی آن فعال بودن حالت روز است. همچنین در صورتی که false باشد، عبارت Night Mode را نشان می‌دهد که معنی آن فعال بودن حالت تیره یا شب است.

حالت تیره در اپلیکیشن ری اکت

اکنون که اپلیکیشن ری‌اکت خود را تنظیم کرده‌ایم، نوبت بررسی CSS رسیده است.

1.App {  
2   text-align: center;  
3   height: 100%; 
4   transition: background-color 0.3s, color 0.3s;
5}

زمانی که حالت تیره انتخاب نشده باشد، CSS ما کاملاً سرراست خواهد بود. از آنجا که سفید رنگ پیش‌فرض پس‌زمینه و سیاه رنگ فونت HTML است، نیازی به ذکر آن‌ها در اینجا وجود ندارد. تنها کاری که باید انجام دهیم، تعیین ارتفاع و عرض App و transition است. با تعیین گذار رنگ پس‌زمینه و گذار رنگ (هر دو روی 0.3 ثانیه) مطمئن می‌شویم که گذار از حالت روز به شب روان خواهد بود. در غیر این صورت این گذار بیشتر شبیه به فلاش زدن دوربین عکاسی خواهد بود. اکنون که استایل‌های پیش‌فرض را در اختیار داریم، به طراحی CSS حالت تیره می‌پردازیم.

1.night {
2  text-align: center;
3  height: 100%;
4  width: 100%;  
5  background-color: black;
6  transition: background-color 0.3s, color 0.3s;
7}

در کد فوق استایل‌هایی برای کلاس دارای نام ‎.night اعلان کرده‌ایم و رنگ پس‌زمینه و رنگ را صراحتاً طوری مشخص ساخته‌ایم که HTML از مقادیر پیش‌فرض استفاده نکند. این استایل نیز گذارهایی به صورت زیر دارد:

1transition: background-color 0.3s, color 0.3s;

بدین ترتیب اطمینان می‌یابیم که وقتی از حالت تیره به حالت روشن جابجا می‌شویم، گذار همچنان روان خواهد بود. اگر به خاطر داشته باشید، className مربوط به کامپوننت App بر اساس مقدار props.mode تعیین می‌شود. اگر props.mode به صورت false باشد از className="App"‎ استفاده می‌کنیم و در غیر این صورت از "className="night استفاده خواهد شد. CSS فوق با تغییر قالب برای کامپوننت App را پیاده‌سازی می‌کند، اما برای این که مطمئن شویم استایل‌های ضروری بر روی همه عناصر فرزند اعمال خواهد شد، باید چند خط کد دیگر نیز اضافه کنیم:

1.night h1, .night h2, .night div, .night textarea{
2  background-color: black;
3  color: white;
4  transition: background-color 0.3s, color 0.3s;
5}

بدین ترتیب رنگ پس‌زمینه و رنگ متن برای هر یک از عناصر h1 ،h2 ،p ،div و textarea که درون کامپوننت App قرار دارند عوض خواهد شد. این عناصر بخش‌های ادیتور متنی اپلیکیشن textarea و عناوین آن (h2) را شامل می‌شوند. h1 عنوان خود اپلیکیشن است و تقریباً هر چیز دیگر یا در کانتینر div خود و یا در کانتینر div والدش قرار دارد. با قرار دادن night. در جلوی همه این عناصر، می‌توانیم این تگ‌های فرزند خاص را در زمان تغییر قالب اپلیکیشن هدفگیری کنیم.

همچنین باید اشاره کنیم که در اینجا از سلکتور descendant استفاده کرده‌ایم که به وسیله استفاده از فاصله بین ‎.night و تگ HTML مشخص می‌شود. بدین ترتیب همه وهله‌های فرزند یک عنصر که زیر ‎.night قرار می‌گیرند، انتخاب خواهند شد. ما از عملگر فرزند (>) استفاده نکرده‌ایم، چون تنها فرزند بی‌واسطه یک عنصر را انتخاب می‌کند. همچنین از عملگر هم‌نیای مجاور (+) نیز استفاده نکردیم، زیرا تنها عناصر هم‌نیا را انتخاب می‌کند. برای مطالعه بیشتر در خصوص انواع سلکتورهای CSS به مقاله زیر مراجعه کنید:

به این ترتیب کار طراحی حالت تیره اپلیکیشن ری‌اکت تقریباً به پایان رسیده است، اما چند نکته دیگر نیز وجود دارند که باید به آن‌ها توجه داشته باشید. نکته نخست این که چند عنصر مانند دکمه‌های آبی هستند که لازم نیست رنگ یا رنگ پس‌زمینه آن‌ها را تغییر دهیم. فرقی نمی‌کند از حالت تیره یا روشن استفاده کنید، این دکمه‌ها همواره باید آبی با آیکون‌های سفید باقی بمانند. برای تضمین این که تغییر className تأثیری روی این دکمه‌ها نمی‌گذارد، CSS زیر را اضافه می‌کنیم:

1.night.buttons{ background-color: navy;}

با قرار دادن خط فوق در فایل App.js مطمئن می‌شویم که CSS قبلی دیگر نمی‌تواند استایل دکمه‌ها را عوض کند. شاید فکر کنید این CSS باید پس از CSS اصلی بیاید، زیرا طرز کار CSS به صورت آبشاری است و از تقدم عملگرها برای تعیین استایلی که باید روی عنصر اعمال شود بهره می‌گیرد.

اما در عمل مهم نیست که این خط کد کجا قرار می‌گیرد. از آنجا که ما از سلکتور کلاس برای هدفگیری دکمه‌ها استفاده می‌کنیم، استایل‌های ‎.night div روی «سطح خصوصیت» (specificity) پایین‌تر از ‎.night.buttons اعمال نمی‌شوند. برای کسب اطلاعات بیشتر در این مورد به این مقاله مراجعه کنید:

منطق فوق را می‌توان در مورد عنصر آخر نیز مورد استفاده قرار دارد. ما می‌خواهیم عنصر کانتینر خروجی از حالت تیره استقلال داشته باشد. این بخش دارای نام کلاس.vew است که کد کاربر در آن اجرا می‌شود و از آنجا که ناحیه خروجی تنها کد نوشته شده از سوی کاربر را نمایش می‌دهد، باید مطمئن شویم که استایل‌های پیش‌فرض اعمال شده‌اند، مگر این که کاربر انواع جدیدی را در بخش CSS وارد کرده باشد.

1.night.view { background-color: white;}

بقیه خروجی در یک iframe درج می‌شود که فرزند ‎.view است. این بدان معنی است که استایل‌های کاربر کاملاً متمایز از استایل‌های اپلیکیشن می‌مانند. جلوگیری از تغییر رنگ پس‌زمینه کانتینر خروجی تنها کاری است که به آن نیاز داریم. نتیجه نهایی به صورت زیر است:

پیاده سازی حالت تیره در اپلیکیشن ری اکت

بدین ترتیب موفق شدیم حالت تیره را در اپلیکیشن ری‌اکت خود پیاده‌سازی کنیم. با چند خط CSS اضافی و کمی منطق props، اپلیکیشن ری‌اکت ما اکنون به صورت مؤثر و بهینه‌ای مجهز به قابلیت حالت تیره یا شب شده است.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۱ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
better-programming
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *