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
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
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
ジョジョの世界をXRで再現する
mofurune
0
180
[Dev Group Paris Octobre 26] Agentforce, SIforce, Claudeforce, Slackbot… on s'y retrouve ?
nabondance
0
110
【加筆修正版】Laravel のアプリケーションをどこにデプロイするか #phpcon_ehime
akase244
0
150
Atomic Design, Enforced: Scaling Mobile Design Systems (next.app devCon / droidCon Berlin 2026)
steliosf
PRO
0
170
Next.js: The final boss of Web Performance
guaca
0
290
全ての永続トークンを、生まれる前に消し去りたい!
sylph01
2
1k
HTML-in-Canvasで作る未来のWeb UI表現
clockmaker
5
5.2k
IBM Bob でAI駆動開発『QC-Playbook』
ichirokano2
0
110
Railsバージョンを4倍にした話
optim
0
470
見えないものを探る要求要件定義に必要な基本的思考 / invisible-requirement-thinking
minodriven
15
8.6k
3回つくってわかった、 定期実行ジョブ基盤の本質情報
takai
0
530
npm との違いを手がかりにGo の依存管理を理解したい
optim
0
930
Featured
See All Featured
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.6k
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
2
2k
How to Ace a Technical Interview
jacobian
280
24k
GraphQLとの向き合い方2022年版
quramy
50
15k
New Earth Scene 8
popppiees
4
2.7k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
Become a Pro
speakerdeck
PRO
31
6.3k
We Have a Design System, Now What?
morganepeng
55
8.4k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
7k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.8k
ラッコキーワード サービス紹介資料
rakko
1
5.4M
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.4k
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