تعرفنا في القسم 2 على طريقتين لإضافة التنسيقات إلى التطبيق، الطريقة القديمة باستخدام ملف CSS واحد وطريقة التنسيق المباشر في المكان.
مكتبات جاهزة للاستخدام مع واجهة المستخدم UI
يمكن استخدام مكتبات جاهزة في إضافة التنسيقات إلى التطبيق. وتعتبر مكتبة الأدوات Bootstrap التي طورتها Twitter، من أكثر إطارات العمل مع واجهة المستخدم شعبية، والتي ستبقى كذلك ربما. ستجد حاليًا عددًا هائلًا من المكتبات التي تنسق واجهة المستخدم، ولديك خيارات واسعة جدًا لا يمكن حصرها في قائمة. تقدم العديد من إطارات عمل UI لمطوري تطبيقات الويب سمات جاهزة و"مكوّنات" كالأزرار والقوائم والجداول. ولقد وضعنا كلمة مكوّنات بين معترضتين لأننا لا نتكلم هنا عن مكوّنات React. تُستخدم إطارات عمل UI عادةً بإدراج ملفات CSS بالإضافة إلى ملفات JavaScript الخاصة بها ضمن التطبيق. تأتي العديد من إطارت عمل UI بنسخ مخصصة للاستخدام مع React، حيث حُوّلت العديد من مكوناتها إلى مكوّنات React. فهنالك نسخ مختلفة من Bootstap مخصصة للعمل مع React مثل reactstrap وreact-bootstrap.
سنطلع تاليًا على إطاري العمل Bootstrap وMaterialUI. وسنستخدمهما لإضافة نفس التنسيقات إلى التطبيق الذي أنشأناه في فصل (مكتبة React-Router) من هذا القسم.
استخدام إطار العمل React-Bootstrap
لنلقي نظرة على Bootstrap مستخدمين الحزمة react-bootstrap. لنثبت هذه الحزمة إذًا:
npm install react-bootstrap
ثم سنضيف رابطًا لتحميل ملف تنسيق CSS الخاص بالإطار Bootstarp ضمن المعرّف <head>
في الملف "public/index.html"
<head> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" /> // ... </head>
سنلاحظ أنّ مظهر التطبيق قد أصبح أفضل عند إعادة تحميله:
تصيّر جميع محتويات التطبيق عند استخدام Bootstrap داخل حاوية. ويتم ذلك عمليًا بإعطاء الصفة classname
للعنصر <div> الجذري القيمة "container".
const App = () => { // ... return ( <div className="container"> // ... </div> ) }
وسنجد تأثير ذلك واضحًا على مظهر التطبيق، فلم يعد المحتوى ملاصقًا لحافة المتصفح كما كانت من قبل:
لنجري بعض التعديلات على المكوّن Notes
، بحيث يصيّر قائمة الملاحظات على شكل جدول. حيث تؤمن React-Bootstrap مكوّن الجدول جاهزًا للاستخدام، فلا حاجة لتعريف أية أصناف CSS مفصلة.
const Notes = (props) => ( <div> <h2>Notes</h2> <Table striped> <tbody> {props.notes.map(note => <tr key={note.id}> <td> <Link to={`/notes/${note.id}`}> {note.content} </Link> </td> <td> {note.user} </td> </tr> )} </tbody> </Table> </div> )
لقد أصبح تنسيق التطبيق أفضل:
لاحظ أنّه عليك إدراج مكونات React-Bootstrap بشكل منفصل من المكتبة كالتالي:
import { Table } from 'react-bootstrap'
النماذج
لنحسّن نموذج تسجيل الدخول بمساعدة نماذج Bootstrap.
تأتي المكتبة React-Bootstrap بمكوّنات مدمجة لإنشاء النماذج (على الرغم من النقص الواضح في توثيق هذا الموضوع):
let Login = (props) => { // ... return ( <div> <h2>login</h2> <Form onSubmit={onSubmit}> <Form.Group> <Form.Label>username:</Form.Label> <Form.Control type="text" name="username" /> <Form.Label>password:</Form.Label> <Form.Control type="password" /> <Button variant="primary" type="submit"> login </Button> </Form.Group> </Form> </div> )}
سيزداد عدد المكونات التي سندرجها شيئًا فشيئًا:
import { Table, Form, Button } from 'react-bootstrap'
سيبدو التطبيق بعد التحوّل إلى نموذج Bootstrap كالتالي:
التنبيهات
سنحسّن التنبيهات أيضًا في تطبيقنا بعد أن حسنّا مظهر النماذج.:
لنضف رسالة إلى التنبيهات عندما يسجل المستخدم دخوله إلى التطبيق، وسنخزّنها ضمن المتغير message
في حالة المكوّن App
:
const App = () => { const [notes, setNotes] = useState([ // ... ]) const [user, setUser] = useState(null) const [message, setMessage] = useState(null) const login = (user) => { setUser(user) setMessage(`welcome ${user}`) setTimeout(() => { setMessage(null) }, 10000) } // ... }
سنصيّر الرسالة على أنها مكون تنبيه Bootstrap. ولاحظ مجددًا أنّ المكتبة React-Bootstrap ستزودنا بالمكون المقابل لمكون Recat.
أدوات التنقل
لنغيّر أخيرًا قائمة التنقل في التطبيق مستخدمين المكوّن Navbar من Bootstrap. تزوّدنا المكتبة Bootstrap بمكونات مدمجة مقابلة. لقد وجدنا من خلال المحاولة والخطأ حلًا مرضيًا، على الرغم من التوثيق غير الواضح:
<Navbar collapseOnSelect expand="lg" bg="dark" variant="dark"> <Navbar.Toggle aria-controls="responsive-navbar-nav" /> <Navbar.Collapse id="responsive-navbar-nav"> <Nav className="mr-auto"> <Nav.Link href="#" as="span"> <Link style={padding} to="/">home</Link> </Nav.Link> <Nav.Link href="#" as="span"> <Link style={padding} to="/notes">notes</Link> </Nav.Link> <Nav.Link href="#" as="span"> <Link style={padding} to="/users">users</Link> </Nav.Link> <Nav.Link href="#" as="span"> {user ? <em>{user} logged in</em> : <Link to="/login">login</Link> } </Nav.Link> </Nav> </Navbar.Collapse> </Navbar>
لشريط التنقل الناتج مظهرًا واضحًا ومريحًا:
إن تغيّر حجم شاشة العرض على المتصفح، سنجد أن القائمة ستختفي تحت زر "الهامبرغر" وستظهر مجددًا بالنقر عليه:
تقدم Bootstrap والعديد من أطر عمل UI تصاميم متجاوبة بحيث تُصيّر التطبيقات بشكل يناسب القياسات المختلفة لشاشات العرض.
ستساعدك أدوات تطوير Chrome على محاكاة استخدام التطبيق ضمن متصفحات أنواع مختلفة من الهواتف النقالة:
يمكنك أن تجد الشيفرة كاملة على GitHub.
إطار العمل Material UI
سنلقي نظرة الآن على المكتبة MaterialUI التي تعمل مع React، والتي تستخدم اللغة المرئية لتصميم المواد والمطوّرة من قبل Google. لنثبت هذه المكتبة:
npm install @material-ui/core
ثم سنضيف السطر التالي إلى المعرّف
في الملف "public/index.html"، حيث يحمًل هذا السطر الخط "Roboto" من تصميم Google:
<head> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" /> // ... </head>
سنستخدم الآن MaterialUI لتنفيذ نفس التغييرات التي أجريناها سابقًا باستخدام Bootstrap.
سنصيّر التطبيق كاملًا ضمن حاوية:
import Container from '@material-ui/core/Container' const App = () => { // ... return ( <Container> // ... </Container> ) }
لنبدأ بالمكوّن Note
ونصيّر قائمة الملاحظات ضمن جدول.
const Notes = ({notes}) => ( <div> <h2>Notes</h2> <TableContainer component={Paper}> <Table> <TableBody> {notes.map(note => ( <TableRow key={note.id}> <TableCell> <Link to={`/notes/${note.id}`}>{note.content}</Link> </TableCell> <TableCell> {note.name} </TableCell> </TableRow> ))} </TableBody> </Table> </TableContainer> </div> )
ستبدو النتيجة كالتالي:
إنّ إدراج كل مكون بشكل منفصل، هي إحدى المزايا غير المرضية في MaterialUI. إذ تكون قائمة المكوّنات التي سندرجها طويلة:
import { Container, Table, TableBody, TableCell, TableContainer, TableRow, Paper, } from '@material-ui/core'
النماذج
سنحسّن مظهر نموذج تسجيل الدخول باستخدام المكوّنين TextField وButton
const Login = (props) => { const history = useHistory() const onSubmit = (event) => { event.preventDefault() props.onLogin('mluukkai') history.push('/') } return ( <div> <h2>login</h2> <form onSubmit={onSubmit}> <div> <TextField label="username" /> </div> <div> <TextField label="password" type='password' /> </div> <div> <Button variant="contained" color="primary" type="submit"> login </Button> </div> </form> </div> ) }
وستكون النتيجة كالتالي:
لا تؤمن MaterialUi مكون خاص بالنماذج كما في Bootstrap. فالنموذج هنا هو نموذج HTML نظامي. وتذكر أن تدرج كل المكوّنات الموجودة في النموذج.
التنبيهات
يمكن عرض التنبيهات باستخدام المكون Alert والذي يشابه تمامًا المكون المقابل في Bootstarp:
<div> {(message && <Alert severity="success"> {message} </Alert> )} </div>
لا تتضمن الحزمة الأساسية للإطار MaterialUI المكوّن Alert بعد، لذلك لا بد من تثبيت الحزمة lab لاستخدامه:
npm install @material-ui/lab
وبعدها يمكننا إدراج المكوّن كالتالي:
import { Alert } from '@material-ui/lab'
سيبدو التنبيه أنيق المظهر:
أدوات التنقل
يمكننا إدراج أدوات التنقل باستخدام المكوّن AppBar . فلو استعملنا المثال الوارد في التوثيق:
<AppBar position="static"> <Toolbar> <IconButton edge="start" color="inherit" aria-label="menu"> </IconButton> <Button color="inherit"> <Link to="/">home</Link> </Button> <Button color="inherit"> <Link to="/notes">notes</Link> </Button> <Button color="inherit"> <Link to="/users">users</Link> </Button> <Button color="inherit"> {user ? <em>{user} logged in</em> : <Link to="/login">login</Link> } </Button> </Toolbar> </AppBar>
سيفي ذلك بالغرض، لكن يمكن أن نحسن شريط التنقل أكثر:
حيث ستجد طرقًا أفضل ضمن التوثيق. إذ يمكن استخدام خصائص المكوّن لتحديد الطريقة التي يُصير بها العنصر الجذري لمكوّن MaterialUI، وذلك كما يلي:
<Button color="inherit" component={Link} to="/"> home </Button>
سيُصيّر المكون Botton
بجيث يكون مكوّنه الأب (الجذري) هو المكوّن Link
من المكتبة react-router-dom ويستقبل مساره من خلال الخاصية to
. ستكون شيفرة أدوات التنقل كالتالي:
<AppBar position="static"> <Toolbar> <Button color="inherit" component={Link} to="/"> home </Button> <Button color="inherit" component={Link} to="/notes"> notes </Button> <Button color="inherit" component={Link} to="/users"> users </Button> {user ? <em>{user} logged in</em> : <Button color="inherit" component={Link} to="/login"> login </Button> } </Toolbar> </AppBar>
وستظهر النتيجة كالتالي:
ستجد الشيفرة كاملة على GitHub.
أفكار ختامية
ليس هناك خلاف واسع بين react-bootstrap وMaterialUI. وسيكون الخيار لك. ويشير معد هذا المنهاج إلى أنه استخدم MaterialUi كثيرًا وكانت انطباعاته الأولى إيجابية. فتوثيق المكتبة أفضل قليلًا. وبناء على إحصاءات موقع https://www.npmtrends.com/ الذي يتابع شعبية مكتبات npm المختلفة فقد تجاوزت شعبية MaterialUI مكتبةReact-Bootstrap عام 2020:
لقد استخدمنا في الأمثلة السابقة إطارات عمل UI بالاستعانة بمكتبات React-integration بدلًا من المكتبة React Bootstrap. وقد كان بمقدورنا استخدامها مباشرةً بتعريف أصناف CSS ضمن عناصر HTML في التطبيق، بدلًا من تعريف الجدول كمكوّن آخر هو Table
على سبيل المثال:
<Table striped> // ... </Table>
حيث يمكننا استخدام جدول HTML اعتيادي وتزويده بصنف CSS المطلوب:
<table className="table striped"> // ... </table>
لن تتوضح فكرة استخدام React-Bootstrap من خلال هذا المثال. فبالإضافة إلى جعل شيفرة الواجهة الأمامية أكثر اختصارًا وأكثر قابلية للقراءة، فالفائدة الأخرى لاستخدام مكتبات React UI هي أنها تتضمن شيفرة JavaScript اللازمة لعمل بعض المكونات الخاصة. إذ تتطلب بعض مكونات React اعتماديات JavaScript والتي نفضل عدم إدراجها في تطبيقات React.
إنّ بعض سلبيات استخدام إطارات عمل UI من خلال مكتبات التكامل بدلًا من استخدامها مباشرةً، هي احتمال وجود واجهات برمجية غير مستقرة ضمن تلك المكتبات أو أنها قد تعاني نقصًا في توثيقها. إلّا أنّ حالة Semantic UI React مثلًا أفضل بكثير من غيرها من إطارت عمل UI، كونها مكتبة تكامل رسمية من مكتبات React.
وهنالك أيضًا تساؤلات حول ضرورة أو عدم ضرورة استخدام إطارت عمل UI أصلًا. وهذا أمر عائد لكل شخص. أما بالنسبة إلى الأشخاص الذين تنقصهم المعرفة بتنسيقات CSS وتصميمات الويب فهي قطعًا أدوات مفيدة.
أطر عمل UI أخرى
سنقدم لك قائمة بأكثر عمل UI قد تناسبك. فإن لم تجد الإطار المفضل لديك موجودًا بينها، فقدم طلب إلغاء هذه القائمة من مادة المنهاج.
- https://bulma.io
- https://ant.design
- https://get.foundation
- https://chakra-ui.com
- https://tailwindcss.com
المكتبة Styled components
هناك أيضًا طرق أخرى في تنسيق تطببيقات React لم نأت على ذكرها بعد. منها المكتبة والتي تقدم طريقة مهمة في تنسيق العناصر من خلال قوالب موسومة مجردة ظهرت للمرة الأولى مع ES6.
لنجري بعض التغييرات على تنسيق تطبيقنا بمساعدة المكتبة السابقة، لكن علينا أولًا تثبيت الحزمة كالتالي:
npm install styled-components
لنعرّف مكوّنين يحملان معلومات تنسيق كالتالي:
import styled from 'styled-components' const Button = styled.button` background: Bisque; font-size: 1em; margin: 1em; padding: 0.25em 1em; border: 2px solid Chocolate; border-radius: 3px; ` const Input = styled.input` margin: 0.25em; `
تنشئ الشيفرة السابقة نسختين تحملا تنسيقًا من عنصرين هما input
وbutton
، ومن ثم تسندهما إلى متغيرين يحملان الاسم ذاته.
إنّ الطريقة التي يُعرّف بها التنسيق مميزة، حيث عُرّفت قواعد تنسيق CSS داخل أقواس. وسيعمل المكوّن الذي يحمل تنسيقًا بنفس الطريقة التي يعمل بها الزر أو عنصر الإدخال النظاميين، كما يمكن استخدامهما بالطريقة ذاتها:
const Login = (props) => { // ... return ( <div> <h2>login</h2> <form onSubmit={onSubmit}> <div> username: <Input /> </div> <div> password: <Input type='password' /> </div> <Button type="submit" primary=''>login</Button> </form> </div> ) }
لننشئ عدة مكونات أخرى لتنسيق هذا التطبيق، وهي عناصر
const Page = styled.div` padding: 1em; background: papayawhip; ` const Navigation = styled.div` background: BurlyWood; padding: 1em; ` const Footer = styled.div` background: Chocolate; padding: 1em; margin-top: 1em; `
لنستخدم هذه المكوّنات في التطبيق:
const App = () => { // ... return ( <Page> <Navigation> <Link style={padding} to="/">home</Link> <Link style={padding} to="/notes">notes</Link> <Link style={padding} to="/users">users</Link> {user ? <em>{user} logged in</em> : <Link style={padding} to="/login">login</Link> } </Navigation> <Switch> <Route path="/notes/:id"> <Note note={note} /> </Route> <Route path="/notes"> <Notes notes={notes} /> </Route> <Route path="/users"> {user ? <Users /> : <Redirect to="/login" />} </Route> <Route path="/login"> <Login onLogin={login} /> </Route> <Route path="/"> <Home /> </Route> </Switch> <Footer> <em>Note app, Department of Computer Science 2020</em> </Footer> </Page> ) }
ستظهر النتيجة كالتالي:
تزداد شعبية هذه المكتبة في الآونة الأخيرة، وقد اعتبرها العديد من المطورين بأنها أفضل الطرق في تنسيق تطبيقات React.
التمارين
يمكن أن تجد التمارين التي تتعلق بمواضيع هذا الفصل، في الفصل الأخير من هذا القسم ضمن مجموعة التمارين (توسيع تطبيق قائمة المدونات).
ترجمة -وبتصرف- للفصل More About Styles من سلسلة Deep Dive Into Modern Web Development
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.