اذهب إلى المحتوى

تعرفنا في القسم 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>

سنلاحظ أنّ مظهر التطبيق قد أصبح أفضل عند إعادة تحميله:

stylish_app_01.png

تصيّر جميع محتويات التطبيق عند استخدام Bootstrap داخل حاوية. ويتم ذلك عمليًا بإعطاء الصفة classname للعنصر <div> الجذري القيمة "container".

const App = () => {
  // ...

  return (
    <div className="container">      
    	// ...
    </div>
  )
}

وسنجد تأثير ذلك واضحًا على مظهر التطبيق، فلم يعد المحتوى ملاصقًا لحافة المتصفح كما كانت من قبل:

bootstrap_style_container_02.png

لنجري بعض التعديلات على المكوّن 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>
)

لقد أصبح تنسيق التطبيق أفضل:

table_style_03.png

لاحظ أنّه عليك إدراج مكونات 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 كالتالي:

notification_style_04.png

التنبيهات

سنحسّن التنبيهات أيضًا في تطبيقنا بعد أن حسنّا مظهر النماذج.:

navbar_style_05.png

لنضف رسالة إلى التنبيهات عندما يسجل المستخدم دخوله إلى التطبيق، وسنخزّنها ضمن المتغير 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>

لشريط التنقل الناتج مظهرًا واضحًا ومريحًا:

navbar_viewport_change_06.png

إن تغيّر حجم شاشة العرض على المتصفح، سنجد أن القائمة ستختفي تحت زر "الهامبرغر" وستظهر مجددًا بالنقر عليه:

chrome_view_simulation_07.png

تقدم Bootstrap والعديد من أطر عمل UI تصاميم متجاوبة بحيث تُصيّر التطبيقات بشكل يناسب القياسات المختلفة لشاشات العرض.

ستساعدك أدوات تطوير Chrome على محاكاة استخدام التطبيق ضمن متصفحات أنواع مختلفة من الهواتف النقالة:

chrome_view_simulation_08.png

يمكنك أن تجد الشيفرة كاملة على 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_table_09.png

إنّ إدراج كل مكون بشكل منفصل، هي إحدى المزايا غير المرضية في 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_form_10.png

لا تؤمن 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'

سيبدو التنبيه أنيق المظهر:

materialui_alert_11.png

أدوات التنقل

يمكننا إدراج أدوات التنقل باستخدام المكوّن 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_navbar_basic_12.png

حيث ستجد طرقًا أفضل ضمن التوثيق. إذ يمكن استخدام خصائص المكوّن لتحديد الطريقة التي يُصير بها العنصر الجذري لمكوّن 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>

وستظهر النتيجة كالتالي:

materialui_navbar_13.png

ستجد الشيفرة كاملة على GitHub.

أفكار ختامية

ليس هناك خلاف واسع بين react-bootstrap وMaterialUI. وسيكون الخيار لك. ويشير معد هذا المنهاج إلى أنه استخدم MaterialUi كثيرًا وكانت انطباعاته الأولى إيجابية. فتوثيق المكتبة أفضل قليلًا. وبناء على إحصاءات موقع https://www.npmtrends.com/ الذي يتابع شعبية مكتبات npm المختلفة فقد تجاوزت شعبية MaterialUI مكتبةReact-Bootstrap عام 2020: 

maerialUi_vs_react_bootstrap_14.png

لقد استخدمنا في الأمثلة السابقة إطارات عمل 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 قد تناسبك. فإن لم تجد الإطار المفضل لديك موجودًا بينها، فقدم طلب إلغاء هذه القائمة من مادة المنهاج.

المكتبة 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>  )
}

ستظهر النتيجة كالتالي:

styled_component_15.png

تزداد شعبية هذه المكتبة في الآونة الأخيرة، وقد اعتبرها العديد من المطورين بأنها أفضل الطرق في تنسيق تطبيقات React.

التمارين

يمكن أن تجد التمارين التي تتعلق بمواضيع هذا الفصل، في الفصل الأخير من هذا القسم ضمن مجموعة التمارين (توسيع تطبيق قائمة المدونات).

ترجمة -وبتصرف- للفصل More About Styles من سلسلة Deep Dive Into Modern Web Development


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...