62

ДАМП 2015 Екатеринбург

Embed Size (px)

Citation preview

Двухуровневаяшаблонизация

Алексей Иванов, Злые Марсиане

Структура доклада1. Стандартный подход к организации верстки и его проблемы

2. Пути решения этих проблем

3. Холивар!

Создаем шаблоныдля интернет‐магазина

Создаем шаблоныдля интернет‐магазина

 

listing.html:

div.listing

div.listing__header

div.listing__breadcrumbs

= render breadcrumbs.slim", items: page.breadcrumbs

h1.listing__title= page.title

div.listing__sorting

= render "sorting.slim", items: page.sorting

div.listing__content

div.listing__items

= render "goods.slim", items: page.goods

div.listing__nav

= render "filters.slim", items: page.filters

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

11.

12.

goods.html:

div.goods

- for item in items do

= render "good.slim", item: item

01.

02.

03.

Сайт запустился!

Добавляембаннеры

 

listing.html:

// ...

div.listing__content

div.listing__items

= render "goods.slim",

items: page.goods,

banners: page.banners

01.

02.

03.

04.

05.

06.

goods.html:

div.goods

- items.each_with_index do |item, i|

- if i%3 == 0

= render "banner.slim", item: banners[i/3-1]

= render "good.slim", item: item

01.

02.

03.

04.

05.

Разный вид дляразных категорий

 

listing.html:

div.listing__view-mode

= render "view-mode.slim", items: page.viewMode

// ...

div.listing__items

= render "goods.slim",

items: page.goods,

banners: page.banner,

mode: page.mode

div.listing__nav

- if page.categories

= render "categories.slim", items: page.categories

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

11.

goods.html:

div.goods

- items.each_with_index do |item, i|

- if type == list

- if i % 3 == 0

= render "banner.slim", item: banners[i/3-1]

= render "good.slim", item: item

- elsif

- if (i+1)%6 == 0

= render "banner.slim", item: banners[(i+1)/6-1]

= render "grid-good.slim", item: item

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

Корневая страницакатегории

 

 

Что можно сделать в такойситуации?

—  Добавить еще пять условий в шаблоны, чтобы избежать копипаста.

—  Решить, что нервы дороже и разнести все это на несколько

шаблонов с повторяющимися элементами.

—  Пойти другим путем.

 

 

 

Что хочется1. Разделять структуру страницы и шаблоны отдельных компонентов

2. Использовать один шаблон на разных страницах с разными детьми.

3. Работать без передачи в шаблон всей информации о его потомках и

их логике работы.

Варинты другого пути—  Extend’ы – путь Django Templates, Twig и производных.

—  Block/Yield – путь haml, Slim, erb и отчасти Jade.

—  Псевдотеги и их разворачивание – путь XSLT и его потомков.

Extend

layout.html:

<div class="listing">

//...

<div class="listing__content">

<div class="listing__items">

{% block items %}{% endblock %}

</div>

<div class="listing__nav">

{% block nav %}{% endblock %}

</div>

</div>

</div>

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

11.

grid.html:

{% extends "listing.html" %}

{% block items %}

{% for item in items %}

//...

{% endfor %}

{% endblock %}

{% block nav %}

//...

{% endblock %}

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

11.

Block/Yield

page.slim:

= render :layout => 'listing.slim', title: title do

= render :layout => 'goods.slim' do

- items.each do |item|

//...

= render :layout => 'nav.slim' do

//...

goods.slim:

div.goods

= yield

01.

02.

03.

04.

05.

06.

01.

02.

XSLT

page.xml:

<listing title={{title}}>

<breadcrumbs items="{{breadcrumbs}}" />

<goods>

// ...

goods.xslt:

<xsl:template match="goods">

<div class="goods">

<xsl:copy-of select="node()"/>

</div>

</xsl:template>

01.

02.

03.

04.

01.

02.

03.

04.

05.

Наследники XSLT—  BEM

—  Web Components и Polymer

—  React

—  Riot 2.0

Чем же они хороши1. Создают компоненты со всем зависимостями.

2. Строят дерево страницы из созданных ранее компонентов.

3. Позволяют вкладывать компоненты друг в друга.

4. Могут работать как на клиенте, так и на сервере.

5. Позволяют описать логику поведения на JS.

6. Дают публичный API для компонента.

Примеры шаблонов сприменением разныхтехнологийhttps://github.com/iAdramelk/dump‐2015‐demo/

Web Components иPolymer

page.html:

<x-listing-nav>

<x-categories items='[...]'></x-categories>

<x-facets>

<x-facet xtitle='Цена, руб.' closed>

<x-price min='900' max='20000'></x-price>

</x-facet>

<x-facet xtitle='Основной материал'>

<x-checkbox-list items='[...]'></x-checkbox-list>

</x-facet>

//...

</x-facets>

</x-listing-nav>

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

11.

12.

facet.html:

<polymer-element name="x-facet"

attributes="xtitle closed">

<template>

<link rel="stylesheet" href="facet.css">

<div class="title"></div>

<div class="content">

<content></content>

</div>

</template>

<script src="facet.js"></script>

</polymer-element>

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

11.

Особенности—  Черновик спецификации для браузера.

—  Shadow DOM.

—  Не требует прекомпиляции.

—  Несколько точек для вставки детей с выбором по css‐селекторам.

listing.html:

//...

<div class="header">

<h1 class="title">{{xtitle}}</h1>

<div class="sorting">

<content select="x-sorting, x-lead"></content>

</div>

</div>

<div class="content">

<div class="items">

<content select="x-listing-main"></content>

</div>

//...

</div>

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

11.

12.

13.

listing.html:

<x-listing xtitle='Заголовок'>

<x-breadcrumbs items="[...]"></x-breadcrumbs>

<x-sorting items="[...]"></x-sorting>

<x-view-mode items="[...]"></x-view-mode>

<x-listing-main>

//...

</x-listing-main>

</x-listing>

01.

02.

03.

04.

05.

06.

07.

08.

Проблемы и ограничения—  Везде кроме Google Chrome нужен полифил.

—  Полифил медленный и заметно тормозит загрузку страницы.

—  Не работает в IE до 10 версии.

React

page.jsx:

<Listing.Nav>

<Categories items=[...] />

<Facets>

<Facet title="Цена, руб." closed={true}>

<Price min="900" max="20000" />

</Facet>

<Facet title="Основной материал">

<CheckboxList items=[...] />

</Facet>

//...

</Facets>

</Listing.Nav>

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

11.

12.

facet.jsx:

var Facet = React.createClass({

componentDidMount: function() {},

render: function() { return (

<div className="facet">

<div className="facet__title">

{this.props.title}

</div>

<div className="facet__content">

{this.props.children}

</div>

</div>

); }

});

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

11.

12.

13.

Особенности—  Создан для быстрой шаблонизации в браузере.

—  Свой синтаксис для компиляции в JavaScript.

—  Очень быстрый, обновляет страницу с минимальными

перерисовками.

—  Генерирует html на сервере как с data‐binding’ами, так и без.

Проблемы и ограничения—  Большой вес скомпилированных шаблонов.

—  Необходимос грузить все шаблоны в браузер для работы data‐

binding’ов.

Riot 2.0

page.html:

<listing-nav>

<categories items="[...]"></categories>

<facets>

<facet title="Цена, руб." closed="{true}">

<price min="900" max="20000"></x-price>

</facet>

<facet title="Основной материал">

<checkbox-list items="[...]"></checkbox-list>

</facet>

//...

</facets>

</listing-nav>

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

11.

12.

facet.tag:

<facet>

<div class="facet{opts.closed ? ' is-closed' : ''}">

<div class="facet__title">{opts.title}</div>

<div class="facet__content">

<inner-html/>

</div>

</div>

this.ready = function() { ... };

</facet>

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

ОсобенностиТот же React, но весит в 20 раз меньше и с более простым

синтаксисом.

Проблемы и ограничения—  Меньше возмонжостей по сравнению со всем остальным.

—  Нет серверного рендеринга.

—  Оставляет теги, использованные для разметки.

—  Нет работающего из коробки способа вставлять теги в теги. Нужно

создавать свой плагин для этого.

—  Совсем новый и слабо обкатан.

BEM

Как работает BEM—  ENB запускает и генерирует все.

—  BEMTREE трансформируется в BEMJSON.

—  На BEMJSON применяются трансформации из BEMHTML или BH.

—  На выходе полученный BEMJSON компилируется в HTML.

page.bemtree:

block('page').mod('bundle', 'listing-list')(

content()(function() {

return [ {

block: 'facets',

content: {

block: 'facet', title: data.title, closed: true,

content: {

block: 'price', min: data.min, max: data.max

}

}

} ]

})

);

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

11.

12.

13.

page.bemjson:

( {

block: 'facets',

content: {

block: 'facet', title: "Размер", closed: true,

content: {

block: 'price', min: 900, max: 20000

}

}

} )

01.

02.

03.

04.

05.

06.

07.

08.

09.

facet.bh.js:

module.exports = function(bh) {

bh.match('facet', function(ctx, json) {

ctx.content({

block : 'facet',

elemMods: { 'closed': json.closed },

content: [

{ elem: 'title', content: json.price },

{ elem: 'content', content: json.content }

]

});

});

};

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

11.

12.

Особенности—  Умеет почти все. Генерировать статику, работать в браузере, делать

логику для блоков без необходимости тащить с собой все шаблоны,

работать с любыми типами данных, и так далее.

—  Можно переназначать не только блоки целиком, но и отдельные

элементы в них.

Проблемы и ограничения—  Нельзя брать по частям.Сразу подписываетесь на весь стек.

—  Очень высокий порог вхождения.

Заключение

Что и где можно использоватьуже сейчас

—  Web Components и Polymer – проекты заточенные под Chrome и

Chrome OS.

—  React – SPA, с необходимостью предзагрузки.

—  Riot – SPA с одной точкой входа.

—  BEM – везде, если сможете разобраться.

Холивар?—  Алексей Иванов, Злые Марсиане

—  Twitter: @iadramelk

—  Github: @iadramelk

—  Примеры и слайды:

https://github.com/iAdramelk/dump‐2015‐demo