Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Владимир Гриненко
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
FrontFest
November 21, 2017
Programming
740
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Владимир Гриненко
FrontFest
November 21, 2017
More Decks by FrontFest
See All by FrontFest
Тим Чаптыков
frontfest
0
1.2k
Егор Банщиков
frontfest
0
900
Jose M. Perez
frontfest
0
760
Алексей Иванов
frontfest
0
1.4k
Екатерина Пригара
frontfest
0
720
Léonie Watson
frontfest
0
790
Кирилл Чернышев
frontfest
0
770
Виктор Грищенко
frontfest
0
660
Игорь Алексеенко
frontfest
0
510
Other Decks in Programming
See All in Programming
ゲームコントローラやキーボードのファームウェアをSwiftで書く
kishikawakatsumi
1
270
App Storeの外へ──日本のiOSサイドローディング入門 for iOSDC Japan 2026
yuukiw00w
0
280
AWSに止められる覚悟してますか?
morizo_1984
2
490
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
270
GitHubハンズオン講座 — 実務レベルのチーム開発のフローを身につけよう
junhat6
0
110
スマートフォンでモールス信号を送受信する 〜スマートフォンのLEDとカメラで作る光通信の設計と実装〜
atsuki_seo
0
210
WebRTC映像をAirPlayに対応させる挑戦.pdf
monolithic_adam
0
330
速習iPhone Duo対応
yuukiw00w
2
910
テストを司るデーモンに会いに行く 〜隔離した仮想マシンでテストを通すまで〜
h1d3mun3
1
600
Starting & Sustaining Code-Based E2E Testing for Non-Coding QA Teams( #jasstniigata )
teyamagu
PRO
1
770
KiroのSpecで「五目並べ」を作ってみる
satoshi256kbyte
1
320
JPUG勉強会 OSSデータベースの内部構造を理解しよう(第2回)
oga5
0
280
Featured
See All Featured
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
270
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
4 Signs Your Business is Dying
shpigford
187
23k
A Tale of Four Properties
chriscoyier
163
24k
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
440
How to Think Like a Performance Engineer
csswizardry
28
2.8k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
840
Navigating the moral maze — ethical principles for Al-driven product design
skipperchong
2
590
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Prompt Engineering for Job Search
mfonobong
0
460
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.2k
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
560
Transcript
Декларативная шаблонизация Владимир Гриненко руководитель службы
Декларативность
Декларативное программирование — это парадигма программирования, в которой задается спецификация
решения задачи, то есть описывается, что представляет собой проблема и
4
Императивно
document Императивно 6
document .querySelectorAll('.link') Императивно 7
document .querySelectorAll('.link') .forEach(link => link.style.color = 'red'); Императивно 8
document .querySelectorAll('.link') .forEach(link => link.style.color = 'red'); document.body.innerHTML += '<a
class="link" href="http://2017.frontfest.ru">FrontFest</a>'; Императивно 9
document .querySelectorAll('.link') .forEach(link => link.style.color = 'red'); document.body.innerHTML += '<a
class="link" href="http://2017.frontfest.ru">FrontFest</a>'; Императивно 10 document.querySelector('.link').classList.remove('link');
Декларативно
.link { color: red } Декларативно 12
library/components/link.css .link { color: red } Декларативно 13 project/components/link.css .link
{ text-decoration: none }
$('.btn').click(function() { $(this) .toggleClass('btn_disabled') .text( $(this).text() === 'Enable' ? 'Disable'
: 'Enable' ); }); Императивно 14
<Btn onToggleDisabled={this.handleToggleDisabled} disabled={this.state.disabled}> {this.state.buttonText} </Btn> Декларативно 15
Шаблонизация
<div class="user"> Elizabeth </div> Шаблонизация 17
<div class="user"> <?php echo $username; ?> </div> Шаблонизация 18
const html = `<div class="user">${username}</div>`; Шаблонизация 19
20
<div class="dropdown"> <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-
haspopup="true" aria-expanded="false"> Dropdown button </button> <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> <a class="dropdown-item" href="#">Action</a> <a class="dropdown-item" href="#">Another action</a> <a class="dropdown-item" href="#">Something else here</a> </div> </div> Шаблонизация 21
<div class="dropdown"> <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-
haspopup="true" aria-expanded="false"> <?php echo $buttonText; ?> </button> <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> <?php for ($i = 1; $i <= count($items); $i++) { ?> <a class="dropdown-item" href="<?php echo $items[$i] ["href"]; ?>"><?php echo $items[$i]["text"]; ?></a> <?php } ?> </div> </div> Шаблонизация 22
<div class="dropdown"> <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-
haspopup="true" aria-expanded="false"> <?php echo $buttonText; ?> </button> <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> <?php for ($i = 1; $i <= count($items); $i++) { ?> <a class="dropdown-item" href="<?php echo $items[$i] ["href"]; ?>"><?php echo $items[$i]["text"]; ?></a> <?php } ?> </div> </div> Шаблонизация 23
Проблемы 24 〉Много писать 〉Много исправлять 〉Невозможно обновиться автоматически
const html = `<div class="user">${username}</div>`; Шаблонизация 25
render() { return ( <div className="user"> {this.props.username} </div> ); }
Компонентный подход 26
<User username="Elizabeth"/> Компонентный подход 27
Проблемы решены 28 〉Много писать 〉Много исправлять 〉Невозможно обновиться автоматически
render() { return ( <div className="user"> {this.props.username} </div> ); }
Еще проблемы 29
render() { return ( <div className="user"> {this.props.hasIcon && <Icon/>} {this.props.username}
</div> ); } Еще проблемы 30
library/components/link.css .link { color: red } Декларативно 31 project/components/link.css .link
{ text-decoration: none }
32
Больше декларативности!
XML + XSLT
<User username="Elizabeth"/> <User username="Elizabeth II" hasIcon="true"/> XML + XSLT 35
<xsl:template match="User"> <div class="user"> <xsl:apply-templates/> <xsl:apply-templates select="@username"/> </div> </xsl:template> XML
+ XSLT 36
<xsl:template match="User[hasIcon=true]"> <xsl:apply-templates select="Icon"/> </xsl:template> XML + XSLT 37
BEMJSON + BEMHTML
{ block: 'user', username: 'Elizabeth' } Полная декларативность 39
{ block: 'user', username: 'Elizabeth' } Полная декларативность 40 <div
class="user"></div>
block('user').content()(node => node.ctx.username); Полная декларативность 41
block('user').content()(node => node.ctx.username); block('user') .match()(node => node.ctx.hasIcon) .content()(node => [
{ block: 'icon' }, applyNext() ]); Полная декларативность 42
block('user').content()(node => node.ctx.username); block('user') .match()(node => node.ctx.hasIcon) .content()(node => [
{ block: 'icon' }, applyNext() ]); Полная декларативность 43
block('user').content()(node => node.ctx.username); block('user') .match()(node => node.ctx.hasIcon) .content()(node => [
{ block: 'icon' }, applyNext() ]); Полная декларативность 44
block('data')( tag()('ul'), elem('item').tag()('li') ); Полная декларативность: теги 45
block('data')( tag()('table'), content()(() => ({ tag: 'tr', content: applyNext() })),
elem('item').tag()('td') ); Полная декларативность: теги 46
<div class="dropdown"> <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-
haspopup="true" aria-expanded="false"> Dropdown button </button> <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> <a class="dropdown-item" href="#">Action</a> <a class="dropdown-item" href="#">Another action</a> <a class="dropdown-item" href="#">Something else here</a> </div> </div> Полная декларативность: реальный пример 47
<div class="dropdown"> <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-
haspopup="true" aria-expanded="false"> <?php echo $buttonText; ?> </button> <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> <?php for ($i = 1; $i <= count($items); $i++) { ?> <a class="dropdown-item" href="<?php echo $items[$i] ["href"]; ?>"><?php echo $items[$i]["text"]; ?></a> <?php } ?> </div> </div> Полная декларативность: реальный пример 48
<div class="dropdown"> <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-
haspopup="true" aria-expanded="false"> <?php echo $buttonText; ?> </button> <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> <?php for ($i = 1; $i <= count($items); $i++) { ?> <a class="dropdown-item" href="<?php echo $items[$i] ["href"]; ?>"><?php echo $items[$i]["text"]; ?></a> <?php } ?> </div> </div> Полная декларативность: реальный пример 49
block('dropdown')( content()(node => [ { block: 'btn', mods: { secondary:
true }, mix: 'dropdown-toggle', attrs: { type: 'button', id: 'dropdownMenuButton', 'data-toggle': 'dropdown', 'aria-haspopup': true, 'aria-expanded': false } }, { elem: 'menu', attrs: { 'aria-labelledby': 'dropdownMenuButton' }, content: applyNext().map(item => ({ elem: 'item', url: item.url, content: item.text })) } ]), Полная декларативность: реальный пример 50 elem('item').replace()(node => ({ block: 'link', mix: node.ctx, url: node.ctx.url, content: node.ctx.content })) )
{ block: 'dropdown', content: [ { elem: 'item', url: 'http://site1.com',
text: 'Site1' }, { elem: 'item', url: 'http://site2.com', text: 'Site2' }, { elem: 'item', url: 'http://site3.com', text: 'Site3' } ] } Полная декларативность: реальный пример 51
const css = require('./css.json'), visited = {}; block('*') .match()(node =>
!visited[node.block]) .replace()(node => { visited[node.block] = true; return [ css[node.block], this.ctx ]; }); Полная декларативность: любой узел 52
53 bem.github.io/bem-xjst
54 github.com/bem/bh-php
$bh->match('button', function ($ctx) { $ctx->tag('button'); }); bh.php 55
Синтаксис может быть любым
React
bem-react-core
Что это 59 〉Обертка над стандартными React-компонентами 〉Полностью совместимая со
стандартными компонентами 〉Не требует знания БЭМ 〉Не требует использования модификаторов 〉Не требует использования уровней переопределения
Что это 60 〉Автоматизирует генерацию классов 〉Позволяет использовать элементы, модификаторы
и миксы 〉Позволяет использовать уровни переопределения 〉Оперирует компонентами, а не путями
None
<div class="user"> Elizabeth </div> Пример 62
export default class User extends Component { render() { return
( <div className="user">{this.props.username}</div> ); } } Было 63
import {decl} from 'bem-react-core'; export default decl({ block: 'user', content({username})
{ return username; } }); Стало 64
export default decl({ block: 'User', willMount() {}, didMount() {}, willReceiveProps()
{}, shouldUpdate() {}, willUpdate() {}, didUpdate() {}, willUnmount() {} }); Livecycle-методы 65
import User from 'b:user'; ReactDOM.render( <User />, //... ); Импорт
66
var User = [ require('path/to/user/user.js') ][0].applyDecls(); ReactDOM.render(<User />); Импорт 67
Траншпилеры 68 〉webpack-bem-loader 〉babel-plugin-bem-import
Какие проблемы решает bem-react-core
Какие проблемы 70 〉Модификации бывают опциональными › отдельные файлы ›
можно выразить через class ButtonWithIcon extends Button
Какие проблемы 71 〉Модификации бывают опциональными 〉Композитные модификации › пересечение
всех вариантов не выражается через наследование › Button, Button_compound, Button_with-icon
import { BaseComponent, warn } from '../../Utilities'; import { ButtonType,
IButtonProps } from './Button.Props'; import { DefaultButton } from './DefaultButton/DefaultButton'; import { CommandButton } from './CommandButton/CommandButton'; import { CompoundButton } from './CompoundButton/CompoundButton'; import { IconButton } from './IconButton/IconButton'; import { PrimaryButton } from './PrimaryButton/PrimaryButton'; Например, кнопка 72 github.com/OfficeDev/office-ui-fabric-react
public render() { const props = this.props; switch (props.buttonType) {
case ButtonType.command: return <CommandButton { ...props } />; case ButtonType.compound: return <CompoundButton { ...props } />; case ButtonType.icon: return <IconButton { ...props } />; case ButtonType.primary: return <PrimaryButton { ...props } />; default: return <DefaultButton { ...props } />; } } Например, кнопка 73
<Button compound primary icon="check"></Button> А теперь с bem-react-core 74 Декларативно!
// Button_type_compound.js import {declMod} from 'bem-react-core'; import React from 'react';
export default declMod(({ type }) => type === 'button', { block: 'Button', mods({ type }) { return { ...this.__base.apply(this, arguments), type }; }, content() { return <Button … /> } }); Модификатор 75
import Button from 'b:Button m:type=compound'; <Button type="compound">my button</Button> Модификатор 76
None
Шаблонизация в bem-react-core 78 〉tag 〉attrs 〉mods 〉cls 〉mix 〉content
Уровни переопределения
Для чего 80 〉Общая библиотека и проекты
Для чего 81 〉Общая библиотека и проекты lego serp images
video news
Для чего 82 〉Общая библиотека и проекты 〉Платформы
Для чего 83 〉Общая библиотека и проекты 〉Платформы common desktop
touch
Для чего 84 〉Общая библиотека и проекты 〉Платформы common desktop
touch pad phone
Для чего 85 〉Общая библиотека и проекты 〉Платформы 〉Дизайн
Для чего 86 〉Общая библиотека и проекты 〉Платформы 〉Дизайн 〉Эксперименты
experiments exp1 exp2 exp3
None
library/components/link.css .link { color: red } Как это работает 88
project/components/link.css .link { text-decoration: none }
[ 'path/to/level1', 'path/to/level2' ] Уровни переопределения 89
/* styles.css */ @import path/to/level1/block1/block1.css; @import path/to/level2/block1/block1.css; Уровни переопределения 90
// blocks/Link/Link.js import decl from 'bem-react-core'; export default decl({ block:
'Link', tag: 'a', attrs(({url}) => ({href: url})) }); <Link url="…">… <a class="Link" href="…">… Уровни переопределения 91
// blocks/Link/Link.js // a11y/blocks/Link/Link.js import decl from 'bem-react-core'; export default
decl({ block: 'Link', attrs() { return { ...this.__base.apply(this, arguments), role: 'link' }; } } <Link url="…">… <a class="Link" href="…" role="link">… Уровни переопределения 92
None
94 github.com/bem/bem-react-core
95 Пишите декларативно!
None
Вопросы?
None
Владимир Гриненко
[email protected]
tadatuta tadatuta tadatuta