React'ивные Panel'і

Що таке панель? Це досить простий компонент, який розбиває видиму область на 2-3 блоку:
  • Шапка. В шапку зазвичай виводиться заголовок і якісь (зазвичай навігаційні елементи правління.
  • Тіло. В тіло панелі виводиться виводиться довільне вміст. Часто цей блок робиться скроллируемым, щоб шапка не йшла з поля зору.
  • Підвал. Опціональний блок. Сюди зазвичай виводять загальну вмісту панелі інформацію та елементи управління.
Не дивлячись на уявну простоту, реалізації зазвичай не такі вже й прості. Пов'язано це з тим, що варіантів його використання безліч.
В шапці може бути, а може не бути:
  • Заголовок. Додатково у нього може бути підзаголовок.
  • Хлібні крихти. Вони можуть бути частиною заголовка, а можуть — підзаголовка.
  • Навігаційні посилання. Такі як "тому", "наступний" і тп.
  • Кнопки. Такі як "відкрити фільтри", "переключити прапор", "закрити вікно" та інші.
Коротше кажучи, в шапці може бути майже що завгодно. У тілі ж, безумовно, повинна бути можливість виводити вміст. У підвалі вміст так само може бути довільним.
Виходить, що у панелі має бути мінімум 3 параметри, які беруть "складне вміст", тобто таке, яке не є плоским текстом, а містить ієрархію вкладених блоків.
Далі йде огляд тих готових рішень, які можна знайти в гуглі. Для кожного вказано розмір реалізації в рядках коду (CLOS). Плюс бонус в кінці, для тих, хто добереться ;-)
ReactJS
wmira/react-panel — 180 CLOS

В шапку виводяться:
  • Опціональна іконка перед заголовком.
  • Власне заголовок.
  • Опціональний набір клікабельних іконок в правій частині шапки.
Розміри тіла за замовчуванням підлаштовуються під вмісту. Полдвал не підтримується.
Приклад використання:
return (
<Panel
title={Привіт, світ!}
titleIcon="icon-idea"
toolbox={[
{
className : "icon-close" ,
onclick : this.onClose.bind( this )
}
]}
>
<p>Ти прекрасний!</p>
</Panel>
)

Резюме: рішення для приватного випадку, в коді бардак, документації немає, тільки один сумнівний приклад використання в дусі jQuery.
react-bootstrap — 235 CLOS

Шапка і підвал розраховані на висновок простого тексту, але є можливість вивести туди що завгодно. Тіло підлаштовується під розмір вмісту і може бути схлопнуто до нульової висоти через прапор.
Приклад використання:
return (
<Panel
header={
<div>
<span class="my-title">Привіт, світ!</span>
<Button
bsStyle="danger"
onclick={ this.onClose.bind( this ) }
>
Закрити
</Button>
</div>
}
footer={
<Button
bsStyle="success"
onclick={ this.onSuccess.bind( this ) }
>
О, так!
</Button>
}
>
<p>Ти прекрасний!</p>
</Panel>
)

Резюме: не дивлячись на милиці з обертанням списку компонент у div і запихання цілого дерева в атрибут можна використовувати майже для всього. Хіба що "схлопываемость" часто буде зайвим вантажем, а коли потрібно щось особливе, то цієї куцої реалізації швидше за все не вистачить.
pivotal-cf/pivotal-ui — 173 CLOS

Шапка розділена на дві секції: ліву (header) і опціональну праву (actions), куди ви можете виводити вміст. Підвал і тіло мають по одній секції. Для тіла можна включити "скроллируемость", щоб панель не вилазила за межі області перегляду.
Приклад використання:
return (
<Panel
className="bg-neutral-10"
header={
<h1>Привіт, світ!</h1>
}
actions={
<DangerButton onclick={ this.onClose.bind( this ) } >
Закрити
</DangerButton>
}
footer={
<PrimaryButton onclick={ this.onSuccess.bind( this ) }>
О, так!
</PrimaryButton>
}
>
<p>Ти прекрасний!</p>
</Panel>
)

Резюме: все ті ж милиці, але реалізація компактніші, не містить майже нічого зайвого і трохи зручніше у використанні.
Велосипед — 44 CLOS
якось не зручно, що частина верстки задається в атрибутах, а частина в тілі. Деякі функції надлишкові, а для реалізації інших доводиться переписувати компонент. А раз все одно рано чи пізно переписувати, то давайте спробуємо переписати так, щоб і гнучко вийшло і без милиць.
function MyPanel({ className , ...props }) {
return (
<div
{ ...props }
className={ `my-panel-root ${ className || " }` }
/>
)
}

function MyPanelTitle({ className , ...props }) {
return (
<h1
{ ...props }
className={ `my-panel-title ${ className || " }` }
/>
)
}

function MyPanelHead({ className , ...props }) {
return (
<div
{ ...props }
className={ `my-panel-head ${ className || " }` }
/>
)
}

function MyPanelBody({ className , ...props }) {
return (
<div
{ ...props }
className={ `my-panel-body ${ className || " }` }
/>
)
}

function MyPanelFoot({ className , ...props }) {
return (
<div
{ ...props }
className={ `my-panel-foot ${ className || " }` }
/>
)
}

Панель складається з 3 опціональних блоків: шапка, тіло підвал. Бонусом: можна додати кілька шапок/тел/підвалів. Для блоків можна використовувати як стандартні компоненти панелі, так і власні, а всередину них поміщати що завгодно.
Щоправда використання трохи ширше, але зате обійшлися без тегів в атрибути:
return (
<MyPanel className="my-panel-skin-pretty">

<MyPanelHead>
<MyPanelTitle>Привіт, світ!</MyPanelTitle>
<button onclick={ this.onClose.bind( this ) } >Закрити</button>
</MyPanelHead>

<MyPanelBody>
<p>Ти прекрасний!</p>
</MyPanelBody>

<MyPanelFoot>
<button onclick={ this.onSuccess.bind( this ) }>О, так!</button>
</MyPanelFoot>

</MyPanel>
)

Резюме: відносно компактне і дуже гнучке рішення, має простий, зрозумілий, правда трохи багатослівний (що в принципі властиво XML) інтерфейс.
$mol_pager — 11 CLOS

Шапка за замовчуванням виводить заголовок. Вміст будь-якого блоку, як і самі блоки можуть бути замінені чим завгодно. Тіло скроллируется, а позиція скролла відновлюється при перезавантаженні.
Реалізація настільки компактна, що її не страшно призвести прямо тут:
$mol_pager $mol_viewer
childs /
< header $mol_viewer
childs < head /
< titler $mol_viewer
childs /
< title
< bodier $mol_scroller
childs < body /
< footer $mol_viewer
childs < foot /

Приклад використання:
$my_app $mol_pager
title \Привіт, світ!
head /
< titler
< closer $mol_clicker_danger
eventClick > eventClose null
childs / \Закрити
body /
\Ти прекрасний!
foot /
< successor $mol_clicker_major
eventClick > eventSuccess null
childs / \О, так!

Резюме: на порядок компактніше реалізація дає тим не менш високу ступінь гнучкості, використання обходиться без милиць, але застосовується досить незвичайний синтаксис, вимагає освоєння. І, так, це не React, а $mol, де інтерфейс теж будується з компонент, що агрегує в собі інші компоненти, але компоненти не пересоздаются при кожному рендерінгу, а кешируются. :-)
Висновки
У JSX можна зробити і так і сяк, але все-одно щось не те. Типові проблеми:
  • Жорсткий некастомизируемый код, що змушує велосипедить кожен раз коли потрібно додати пару перламутрових гудзиків.
  • Зайві функції в загальних компонентах. Наслідок високої жорсткості коду.
  • Розлогий, непослідовний інтерфейс використання. Зазвичай вміст тіла передається способом відмінним від вмісту інших блоків.
  • Всі програмісти на реакте програмують по різному. Хто зрозумів — той так і фигачит. І швидше за все не так, як потрібно вам.
  • JSX схожий на XML і JavaScript, однак не є ні над-, ні помножеством ні того, ні іншого. Так що за уявною простотою ховається необхідність розбиратися в особливостях унікального синтаксису.
  • Навіть простий компонент вимагає досить багато коду. І чим гнучкіше ви захочете зробити, тим заплутаніше вийде код.
  • Структура компонента, рівним шаром розтікається по його логіці. Мімікрія під XML в цьому випадку стає марною.
  • Залучення верстальника можливо тільки після інтенсивного курсу з JS… після чого він звільняється і йде працювати програмістом. :-)
З іншого боку, є простий й послідовний синтаксис view.tree, оптимізований для створення гнучких компонент з мінімумом вихідного коду, яким можна навчити будь-верстальника в лічені дні, після чого і його ефективність значно підвищиться (йому не доведеться копіпаст величезні шматки html або вручну накликивать потрібні стану компонентів) і ефективність програміста (йому не доведеться "натягувати" верстку на логіку кожен раз, коли верстальник оновить макет).
Навіть якщо ви різноробочий full-stack програміст, який вміє і патерни, і в семантику, і в стилі — ваша ефективність все-одно підвищиться за рахунок зменшення обсягів коду і легкого і невимушеного створення компонент (щоб створити найпростішу компоненту достатньо створити файл з вмістом з однією короткою рядка).
А як би ви реалізували компонент "Панель" на вашому улюбленому фреймворку?
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.