å
é±ã
BBCã¯ãã¡ã€ã³ããŒãžã®æ°ããããŒãžã§ã³ã«Yandexã§äœæãããBEMæ¹æ³è«ã䜿çšãã
ãšè¿°ã¹ãŸããã ãã®æ©äŒã«ãã¯ãŒã¯ã·ã§ããã
BEMãã¯ãããžãŒã®å®å
šãªã¹ã¿ãã¯ã§ãŒããããµã€ããéçºãã ãã®è³æãåéãããããžã§ã¯ãã§BEMãã¯ãããžãŒã®å®å
šãªã¹ã¿ãã¯ã®äœ¿çšãéå§ããæ¹æ³ã説æããããšã«ããŸããã
BEMã¯ãè¿
éã«äœæããŠé·æéç¶æããå¿
èŠããããµã€ãã®éçºãç°¡çŽ åããŸãã ãã®ãã¯ãããžãŒã¯ãã»ãŒãã¹ãŠã®YandexãµãŒãã¹ã®ããã³ããšã³ãã§äœ¿çšãããŠããããã§ã«å€ãã®ã©ã€ãã©ãªãšããŒã«ãååŸããŠããŸãã

ãã®èšäºã§ã¯ãç¬ç«ãããããã¯ã®ã¬ã€ã¢ãŠãã®å©ç¹ãšãªãŒããŒã©ã€ãã¬ãã«ã«ã€ããŠèª¬æããæ¢è£œã®ãããã¯ã©ã€ãã©ãªãšã¢ã»ã³ããªãèªååããããŒã«ã«ã€ããŠèª¬æããŸãã
autoprefixer ãcss-preprocessor
Stylus ãã¢ãžã¥ã©ãŒã·ã¹ãã
YModuleãªã©ã®ããŸããŸãªããŒã«ãéçºè
ã®ç掻ãã©ã®ããã«ç°¡çŽ åããBEMéçºããã»ã¹ã«çµã¿èŸŒããšæ¬åœã«äŸ¿å©ãªãã©ãããã©ãŒã ãäœæãããã瀺ããŸãã
çããäŸã䜿çšããŠãCSSãšJavaScriptã®äž¡æ¹ã«åãã¢ã€ãã¢ã䜿çšã§ããå Žåã宣èšåã¢ãããŒãã®äœ¿ç𿹿³ã説æããŸãã 宣èšåãã³ãã¬ãŒã
BEMHTMLããã³
BEMTREEã«ã€ããŠ
åå¥ã«èª¬æããŸãããããã®ãã³ãã¬ãŒã
ã«ãã ãããŒã¿ã
BEMJSON圢åŒã§èšè¿°ãããHTMLã§èšè¿°ãããBEMããªãŒã«å€æã§ããŸãã BEMæ¹æ³è«ã«åŸã£ãŠãã¢ããªã±ãŒã·ã§ã³ã®ãµãŒããŒéšåãäœæããæ¹æ³ãè©³çŽ°ã«æ€èšããŠã¿ãŸãããã
Twitter APIã䜿çšããŠãããžã§ã¯ããäœæããŸãã ãã®çµæãBEMãã¯ãããžãŒã®å®å
šãªã¹ã¿ãã¯ã«é¢ããäœæ¥ãµã€ããšãããããã¹ãŠãåçŸããæ¹æ³ã«é¢ããæ®µéçãªèšäºãå
¥æã§ããŸãã
ç¹ã«ãã¹ã¿ãŒã¯ã©ã¹ã«ã€ããŠã¯ãããŸããŸãªãœãŒã·ã£ã«ãããã¯ãŒã¯ãæ€çŽ¢ããçµæãæŽç¶ãšãã圢åŒã§è¡šç€ºãããããµãŒãã¹ãäœæããŸããã
github.com/bem/sssrãªããžããªã®githubã«æçš¿ããŸãã-ã
åç
§ããŠãã ãã ã
ãããŠé çªã«è¡ããŸãã
çè«
BEMãšã¯
BEMïŒåèªã®ç¥èª-ããã¯ãèŠçŽ ãããã³ä¿®é£ŸåïŒã¯ãç¹å®ã®å®è£
ãã¯ãããžã«é¢é£ä»ããããŠããªããšã³ãã£ãã£ãèšè¿°ããæ¹æ³ã§ããããã°ã©ã ãšã€ã³ã¿ãŒãã§ã€ã¹ãéçºããããã®æ¹æ³è«ã§ãã
- ãããã¯ã¯ãã¢ããªã±ãŒã·ã§ã³ã®ç¬ç«ããã³ã³ããŒãã³ãã§ãã ä»ã®ãããã¯ããç¬ç«ããŠãããä»ã®ãããã¯ãèŠçŽ ãå«ãå ŽåããããŸãã
- èŠçŽ ã¯ãåå¥ã®æ©èœãæ
åœãããããã¯ã®äžéšã§ãã ãããã¯ããåé¢ããŠãæå³ããããŸããã
- 修食åã¯ããã®å€èгãŸãã¯åäœãæ
åœãããããã¯ãŸãã¯èŠçŽ ã®ããããã£ã§ãã 修食åã¯ããããã¯ãŸãã¯èŠçŽ ã®ç¶æ
ãèšè¿°ããŸãã
BEMã¯ãDOMããªãŒãæœè±¡åããŸãã ãããã¯ã¯äºãã«ç¬ç«ããŠããããã¹ãŠã®æ©èœãšèŠçŽ ãã«ãã»ã«åããŠããŸãã ãããã¯ãå®è£
ãããHTMLã¿ã°ïŒ
div
ãŸãã¯
form
ïŒã¯éèŠã§ã¯ãããŸãããããããã€ã§ã倿Žããããã©ãããŒã远å ãããã§ããŸãã 倿Žãæ®ãã®ãããã¯ã«åœ±é¿ããããšã¯ãããŸããã HTMLã¿ã°ã§ã¯ãªããã€ã³ã¿ãŒãã§ã€ã¹ã³ã³ããŒãã³ãã䜿çšããŠã¢ããªã±ãŒã·ã§ã³ã説æããŸãã
åãããã¯ã¯ããã¡ã€ã«ã·ã¹ãã å
ã®ç¬èªã®ãã©ã«ããŒã«ããããããã¯ããã®èŠçŽ ãããã³ä¿®é£Ÿåãèšè¿°ãããã¹ãŠã®ãã¯ãããžãŒãå«ãŸããŠããŸãã
desktop.blocks/ input/ __box/ # __clear/ # __control/ # _focused/ # _type/ # input.css # css input.js # js input.ru.md # markdown âŠ
BEMãã©ã®ããã«ããªãç»å Žãããã«ã€ããŠè©³ããç¥ãããå Žåã¯ãVitaly Kharisovã®èšäºã
BEMã®æŽå² ããèªã¿ã
ãããªã¬ããŒããã芧ãã ããã
BEMæ¹æ³è«ã®è©³çްãªèª¬æã¯ã
åœç€Ÿã®Webãµã€ãã«ãããŸãã
ãããžã§ã¯ããã©ã³ã¯ã®äœæ
ä»äºã«å¿
èŠãªãã®ããã¹ãŠã€ã³ã¹ããŒã«ããŸãã
ãŸããã¿ãŒããã«ãš
git
ããŒãžã§ã³ç®¡çã·ã¹ãã ãå¿
èŠã§ãã
git-scm.comããã€ã³ã¹ããŒã«ã§ããŸãã
ã»ãšãã©ãã¹ãŠã®ããŒã«ã¯JavaScriptã§èšè¿°ãããŠããããã
node.jsãŸãã¯
io.jsãå¿
èŠã«ãªããŸãã
ãããžã§ã¯ãã®ãã©ã³ã¯ãäœæããã«ã¯ã
generator-bem-stub generatorã䜿çšããŸãã
> npm install -g generator-bem-stub
次ã«ããžã§ãã¬ãŒã¿ãŒèªäœãå®è¡ããŸãã
> yo bem-stub
䜿çšãããŠããæè¡ã«é¢ãã質åã«çãããšãçµã¿ç«ãŠã®ããã«äºåã«çµã¿ç«ãŠãããæ§æããããã©ã³ã¯ãåŸãããŸãã
次ã®åé¡ã調ã¹ãŠã¿ãŸãããã

ã¹ã¯ãªãŒã³ã·ã§ããã¯ã質åã«å¯Ÿããåçã®çµæã瀺ããŠããŸãã æåã®3ã€ã®è³ªåã¯æããã§ãããã®åŸãè峿·±ãéšåãå§ãŸããŸãã
Choose a toolkit to build the project
ïŒäœ¿çšããã³ã¬ã¯ã¿ãŒïŒ -ENBããŒã«ã䜿çšããŸãã ããã¯ããããžã§ã¯ããçµã¿ç«ãŠããŠãŒãã£ãªãã£ã§ããã¹ã¿ã€ã«ãã¹ã¯ãªããããã³ãã¬ãŒããæ¥çããããŒãžå®£èšããããã¯ã®äŸåé¢ä¿ãæ§æãã¡ã€ã«ã«åŸã£ãŠã³ã³ãã€ã«ããã³æé©åããŸããSpecify additional libraries if needed
ããŸãïŒè¿œå ã®ã©ã€ãã©ãªã䜿çšããŸããïŒ-ãã®ãããžã§ã¯ãã§ã¯ã bem-componentsãããã¯ã©ã€ãã©ãªã䜿çšããŸãã ãªãã·ã§ã³ã®ã¹ã¿ã€ã«ããŒãããããŸãã
äœããæ€èšããæã
ã
åå®çŸ©ã¬ãã«
ããã¯ãããã¯å®è£
ã®ã»ããã§ãã ãããžã§ã¯ãã«ã¯è€æ°ã®ã¬ãã«ããããåã¬ãã«ã§ãããã¯ã®å®è£
ã远å ãŸãã¯å€æŽãããŸãã ãããã¯ã®æçµå®è£
ã¯ãæå®ãããé åºã§ãã¹ãŠã®ã¬ãã«ããé çªã«åéãããŸãã
ãããžã§ã¯ãã®åå®çŸ©ã¬ãã«ã§ãã¹ã¿ã€ã«ããã³ãã¬ãŒãããããã¯ã®JavaScriptå®è£
ãåå®çŸ©ããã³åå®çŸ©ã§ããŸãã åæã«ãã©ã€ãã©ãªã®ãœãŒã¹ãã¡ã€ã«ã«ã¯äœã倿ŽããªããããæŽæ°ãããå Žåã¯å€æŽãä¿åã§ããŸãã
ããããã¡ã€ã«ã·ã¹ãã ã§ã©ã®ããã«èŠãããã®äŸã次ã«ç€ºããŸãã
⊠libs/ bem-components/ desktop.blocks/ input/ input.css desktop.blocks/ input/ input.css âŠ
ãããžã§ã¯ãã®
desktop.blocks
ã¬ãã«ã§ãããã¯ãäœæããããšã«ãããå¿
èŠãªãã¯ãããžãŒããªãŒããŒã©ã€ããŸãã¯ãªãŒããŒã©ã€ãã§ããŸãã
äžèšã®äŸã§ã¯ã
CSS
ãã¯ãããžãŒã«å®è£
ã远å ããããšã«ããã
input
ãããã¯ã®ã¹ã¿ã€ã«ãç·šéã§ããŸãã
ããã§ããã©ãããããžã§ã¯ãã®æºåãã§ããŸããã ãããžã§ã¯ããã£ã¬ã¯ããªã«ç§»åããŸãããã
> cd sssr-tutorial
ã¬ã€ã¢ãŠã
ãŸããããŒãžã®éçãããã¿ã€ããäœæããŸãã ãã®æ§é ã説æããããã«ã
BEMJSONãã¯ãããžãŒã䜿çšããŠ
ããŸãã
BEMJSONã¯ãBEMããªãŒã説æããŸãããããã¯ã®é åºãšãã¹ããBEMãšã³ãã£ãã£ã®ååãšç¶æ
ã远å ã®ä»»æã®ãã£ãŒã«ãã
çæããããããžã§ã¯ããåéããŠãäœãèµ·ãã£ãã®ãèŠãŠã¿ãŸãããã ããŒã«ã«ã«ã€ã³ã¹ããŒã«ããã
ENB
ããã±ãŒãžã䜿çšããŠäŸ¿å©ã«äœæ¥ããã«ã¯ã次ã®ã³ãã³ããå®è¡ããå¿
èŠããããŸãã
> export PATH=./node_modules/.bin:$PATH
ãŸãã¯ãã
./node_modules/.bin/
ãµããã£ã¬ã¯ããªããæåã§
enb
ã³ãã³ããå®è¡ããŸã
ãã«ãããã«ã¯ã
enb server
ã³ãã³ãã䜿çšã
enb server
ã
> enb server
httpïŒ// localhostïŒ8080 / desktop.bundles / index / index.htmlãã³ã¬ã¯ã¿ãŒã¯ãå¿
èŠãªãã¹ãŠã®äŸåé¢ä¿ãåéãããããããå¿
èŠãªãããã¯ãšãã¯ãããžãŒã®ãã¡ã€ã«ãåéããŸãã

ãã©ãŠã¶ã§ã€ã³ã¹ãã¯ã¿ãŒãéããDOMããªãŒã確èªããŸãã ãŸã ã³ãŒããèšè¿°ããŠããŸãããããã®ããŒãžã«ã¯æ¢ã«HTMLãçæãããŠããŸãã ããã¯ãã©ã€ãã©ãªã®ãã³ãã¬ãŒãã䜿çšãããŠããããã§ãã ããšãã°ã
bem-core
ã©ã€ãã©ãªã®
page
ãããã¯ãã³ãã¬ãŒãã¯ãããŒãž
doctype
ïŒ
doctype
ã
html
ã
head
ã
body
ãªã©ïŒãçæããŸãã
ãããžã§ã¯ãã®
./desktop.bundles/index/
ãã©ã«ããŒã«
index.bemjson.js
ãã¡ã€ã«ãå«ãŸããŠ
./desktop.bundles/index/
ãŸãã
({ block: 'page', title: 'Hello, World!', styles: [ { elem: 'css', url: 'index.min.css' } ], scripts: [ { elem: 'js', url: 'index.min.js' } ], content: [ 'Hello, World!' ] })
ãã®ãã¡ã€ã«ã¯ãBEMçšèªã§ã®ããŒãžã®èª¬æã§ãã BEMããªãŒã®ã«ãŒããããã¯ã¯
page
ã§ãã
favicon
远å ããŒã¯ãŒã-
title
ã
favicon
ãªã©ããããŸãã ãã®ãããã¯ã®ãã³ãã¬ãŒãã¯
bem-coreã©ã€ãã©ãªã«ãããŸãã
ãã®ã¢ããªã±ãŒã·ã§ã³ã¯ããã£ãããšã³ã³ãã³ããšãã2ã€ã®äž»èŠéšåã§æ§æãããŠããŸãã
sssr
ãããã¯ãããŒãžã³ã³ãã³ãã«è¿œå ããŸãããã®ã³ã³ãã³ãã§ã¯ãã€ã³ã¿ãŒãã§ã€ã¹ã®äžéšãèŠçŽ ãšããŠèšè¿°ãããŸãã ãããè¡ãã«ã¯ã.
./desktop.bundles/index/index.bemjson.js
/
./desktop.bundles/index/index.bemjson.js
/
./desktop.bundles/index/index.bemjson.js
ç·šéã
./desktop.bundles/index/index.bemjson.js
ã
({ block: 'page', //⊠content: [ { block: 'sssr', content: [ { elem: 'header' }, { elem: 'content' } ] } ] });
ããããŒã«ã¯ãæ€çŽ¢ãã©ãŒã ãšããŽä»ãã®ãµã€ãåãå«ãŸããŸãã
{ block: 'sssr', content: [ { elem: 'header', content: [ { elem: 'logo', content: 'Social Services Search Robot:' }, { block: 'form', content: [ { elem: 'search' }, { elem: 'filter', content: '[x] twitter' } ] } ] }, { elem: 'content' } ] }

bem-components
ã©ã€ãã©ãªã®
input
ã
button
ã
spin
ãããã³
checkbox
ãããã¯ã䜿çšã
input
ã ãããžã§ã¯ãã§ã¯ããã®ã©ã€ãã©ãªã¯
./libs/bem-components
ãã©ã«ããŒã«ãããŸãã ãããã®åãããã¯ã«ã¯ç¬èªã®APIããããAPI
ã¯ããã¥ã¡ã³ãã«èšèŒã
ããŠããŸã ã
BEMJSONã«å¿
èŠãªãããã¯ã远å ããŸãã
{ block: 'sssr', content: [ { elem: 'header', content: [ { elem: 'logo', content: [ { block: 'icon', mods: { type: 'sssr' } }, 'Social Services Search Robot:' ] }, { block: 'form', content: [ { elem: 'search', content: [ { block: 'input', mods: { theme: 'islands', size: 'm', 'has-clear' : true }, name: 'query', val: '#b_', placeholder: 'try me, baby!' }, { block: 'button', mods: { theme: 'islands', size: 'm', type: 'submit' }, text: '' }, { block: 'spin', mods: { theme: 'islands', size : 's' } } ] }, { elem: 'filter', content: '[] twitter [] instagram' } ] } ] } ] }
mods
ãã£ãŒã«ãã¯ãã®BEMJSONã¹ããããã«ãããŸãã 䜿çšããã修食åãšãã®æå³ã瀺ããŸãã
mods
ãã£ãŒã«ãã«ã¯
:
-
mods: { type: 'sssr' }
ãŸãã
BEMJSONã§ä»»æã®JavaScriptåŒã䜿çšã§ããŸãã
checkbox
ãããã¯ãç¹°ãè¿ãããã®
map
ã³ã³ã¹ãã©ã¯ãã
filter
èŠçŽ ã®
content
ãã£ãŒã«ãã«è¿œå ã
map
ã
//⊠{ elem: 'filter', content: ['twitter', 'instagram'].map(function(service) { return { block: 'checkbox', mods: { theme: 'islands', size: 'l', checked: service === 'twitter' }, name: service, text: service }; }) } //âŠ
å®å
šãª
index.bemjson.js
ãã¡ã€ã«ïŒ
({ block: 'page', title: 'Social Services Search Robot', favicon: '/favicon.ico', head: [ { elem: 'meta', attrs: { name: 'description', content: 'find them all' }}, { elem: 'css', url: '_index.css' } ], scripts: [{ elem: 'js', url: '_index.js' }], content: { block: 'sssr', content: [ { elem: 'header', content: [ { elem: 'logo', content: [ { block: 'icon', mods: { type: 'sssr' } }, 'Social Services Search Robot:' ] }, { block: 'form', content: [ { elem: 'search', content: [ { block: 'input', mods: { theme: 'islands', size: 'm', 'has-clear' : true }, name: 'query', val: '#b_', placeholder: 'try me, baby!' }, { block: 'button', mods: { theme: 'islands', size: 'm', type: 'submit' }, text: '' }, { block: 'spin', mods: { theme: 'islands', size : 's' } } ] }, { elem: 'filter', content: ['twitter', 'instagram'].map(function(service) { return { block: 'checkbox', mods: { theme: 'islands', size: 'l', checked: service === 'twitter' }, name: service, text: service }; }) } ] } ] }, { elem: 'content' } ] } })
ã€ã³ã¿ãŒãã§ã€ã¹ã®æ§é ã説æããåŸããããã¯ã®ã¹ã¿ã€ã«ãèšè¿°ããã³åå®çŸ©ããå¿
èŠããããŸãã ãã¹ãŠã®äž»èŠãªã¹ã¿ã€ã«ã¯ã
bem-components
ã©ã€ãã©ãªã§æäŸãããŸãã ãã®ãããããªã远å ããå¿
èŠããããŸãã
Stylus CSSããªããã»ããµã䜿çšããŠã¹ã¿ã€ã«ãèšè¿°ããŸãã
*.styl
ãæã€ãã¹ãŠã®ãã¡ã€ã«ã¯ãããªããã»ããµã«ãã£ãŠåŠçãããæçµçãªCSSãã¡ã€ã«ã«æ¥çãããŸãã ããªããã»ããµã§åŠçããå¿
èŠã®ãªãã¹ã¿ã€ã«ã«ã¯ã
*.css
æ¡åŒµåã䜿çšããããšãã§ã
*.css
ã
ãã¡ã€ã«
./desktop.blocks/form/form.styl
form
ãããã¯ã®ã¹ã¿ã€ã«ã
./desktop.blocks/form/form.styl
ããŸãã
.form { display: flex; &__search { margin-right: auto; } .input { width: 400px; } .checkbox { display: inline-block; margin-left: 15px; user-select: none; vertical-align: top; } }
./desktop.blocks/page/page.css
ãã¡ã€ã«ã®
page
ãããã¯ã®å ŽåïŒ
.page { font-family: Tahoma, sans-serif; min-height: 100%; margin: 0; padding-top: 100px; background: #000; }
ãã¡ã€ã«
./desktop.blocks/sssr/sssr.styl
sssr
ãããã¯ã®
./desktop.blocks/sssr/sssr.styl
ïŒ
.sssr { &__header { position: fixed; z-index: 1; top: 0; box-sizing: border-box; width: 100%; padding: 10px 10%; background: #f6f6f6; box-shadow: 0 0 0 1px rgba(0,0,0,.1), 0 10px 20px -5px rgba(0,0,0,.4); .button { margin-left: 10px; } } &__logo { font-size: 18px; margin: 0 0 10px; } &__content { padding: 10px 10%; column-count: 4; column-gap: 15px; transition: opacity .20s linear; } a[rel='nofollow'], a[xhref], [name][server] { text-decoration: none; color: #038543; } }
ãããŠã
user
ãããã¯
desktop.blocks/user/user.styl
ïŒ
.user { &__name { display: inline-block; margin-right: 10px; text-decoration: none; color: #000; &:hover { text-decoration: underline; color: #038543; } } &__post-time { font-size: 14px; display: inline-block; color: #8899a6; } &__icon { position: absolute; right: 5px; bottom: 5px; width: 30px; height: 30px; border-radius: 3px; } }
CSSã¬ã€ã¢ãŠãã®åé¡ã«ã€ããŠã¯è©³ãã説æããŸãããå
ã«é²ã¿ãŸãããã
èŠã€ãã£ãã¡ãã»ãŒãžã«ãããã¯ã远å ããããšã¯æ®ããŸãã ãããã
index.bemjson.js
説æããJavaScriptæ©èœã䜿çšããŠãããã¿ã€ããäœæããŸãã
{ elem: 'content', content: (function() { return 'BEM is extermly cool'.split('').map(function() { var service = ['twitter', 'instagram'][Math.floor(Math.random()*2)]; return { service: service, user: [{ login: 'tadatuta', name: 'Vladimir', avatar: 'https://raw.githubusercontent.com/bem/bem-identity/master/sign/_theme/sign_theme_batman.png' }, { login: 'dmtry', name: 'Dmitry', avatar: 'https://raw.githubusercontent.com/bem/bem-identity/master/sign/_theme/sign_theme_captain-america.png' }, { login: 'sipayrt', name: 'Jack Konstantinov', avatar: 'https://raw.githubusercontent.com/bem/bem-identity/master/sign/_theme/sign_theme_ironman.png' }, { login: 'einstein', name: 'Slava', avatar: 'https://raw.githubusercontent.com/bem/bem-identity/master/sign/_theme/sign_theme_robin.png' }][Math.floor(Math.random()*4)], time: Math.floor((Math.random()*12)+1) + 'h', img: service === 'instagram' ? 'http://bla.jpg' : undefined, text: [ ' â . ( ).', ' â .', ' .'][Math.floor(Math.random()*3)] }; }).map(function(dataItem) { return { block: 'island', content: [ { elem: 'header', content: { block: 'user', content: [ { block: 'link', mix: { block: 'user', elem: 'name' }, url: 'https://www.yandex.ru', target: '_blank', content: dataItem.user.name }, { elem: 'post-time', content: dataItem.time }, { block: 'image', mix: { block: 'user', elem: 'icon' }, url: dataItem.user.avatar, alt: dataItem.user.name } ] } }, { elem: 'text', content: dataItem.text }, { elem: 'footer', content: [ { block: 'service', mods: { type: dataItem.service } } ] } ] }; }); })() }
island
ãããã¯ã®ã¹ã¿ã€ã«ã
./desktop.blocks/island/island.styl
ãã¡ã€ã«ã«
./desktop.blocks/island/island.styl
ãŸãã
.island { font-size: 18px; line-height: 140%; position: relative; display: inline-block; box-sizing: border-box; width: 100%; margin-bottom: 15px; padding: 15px 5px 5px 15px; border-radius: 3px; background: #fff; box-shadow: inset 0 0 1px rgba(0, 0, 0, .4); &__footer { margin-top: 10px; } &__image { display: block; width: 100%; border-radius: 3px; } }
çµæãèŠãŠã¿ãŸãããïŒ

BEMHTMLãã³ãã¬ãŒããšã³ãžã³
宣èšçãªæšæºå
Yandexã¯å®£èšæ§ãéåžžã«å¥œãã§ã-CSSã ãã§ãªãããã³ãã¬ãŒããšJavaScriptã§ãã
CSSã®å®£èšæ§ã¯æ¬¡ã®ããã«ãªããŸãã
.menu__item { display: inline-block; }
menu
display: inline-block;
ãã¹ãŠã®
item
èŠçŽ ã«å¯ŸããŠ
display: inline-block;
ã¹ã¿ã€ã«ãé©çšãã
display: inline-block;
ãã€ãŸã åŠçæ¹æ³ã宣èšããŸã
æ¡ä»¶ã«ãã£ãŠéžæãããDOMããŒãïŒ
{ }
æ¡ä»¶ã«äžèŽããDOMããªãŒã®ãã¹ãŠã®ããŒããéžæãããã³ãã¬ãŒãæ¬äœããããã«é©çšããŸãã
宣èšçãªãã³ãã¬ãŒãåã®ããã«ãYandexã¯ç¬èªã®BEMHTMLãã³ãã¬ãŒããšã³ãžã³ãäœæããŸããã ã¢ãŒããã¯ãã£ã®è©³çްã«ã€ããŠã¯ãèšäº
bem-coreã®ããŒã¿ãã³ãã¬ãŒããåç
§ããŠãã ããã
BEMHTMLã®å®£èšåãã³ãã¬ãŒãã®äŸïŒ
block('menu').elem('item').tag()('span');
æ¡ä»¶ã«äžèŽãããã¹ãŠã®BEMããªãŒãããã¯ãéžæããããã³ãã¬ãŒãæ¬äœããããã«é©çšãããŸãã
()( )
BEMHTMLã¯JavaScriptã§èšè¿°ãããŠããŸãã ãã®æ§æã¯çŽç²ãªJavaScriptã§ãã JavaScript颿°ããµãè¿°èªãšãã³ãã¬ãŒãã®æ¬æã§äœ¿çšã§ããŸãã ãããã¯ã·ã§ã³ã¢ãŒãã®å Žåããã³ãã¬ãŒãã¯æé©åãããJavaScriptã«ã³ã³ãã€ã«ãããŸãã
BEMHTMLã¯ãBEMããªãŒãHTMLæååã«å€æããæ¹æ³ãæ
åœããŸãã å
¥åã¯ãBEMããªãŒãŸãã¯BEMJSONãã¯ãããžã§èšè¿°ããããã®ãã©ã°ã¡ã³ãã§ãã ãã®BEMJSONã¯ãBEMHTMLãã³ãã¬ãŒãã«éããããŸãã ãããŠãåºåã¯HTMLæååã§ãã
äžè¬çã«ããã³ãã¬ãŒãã¯æ¬¡ã®ãšããã§ãã
match(1, 2, 3)()
ãµãã¬ãã£ã±ãŒãã¯ããã¿ãŒã³ãé©çšãããæ¡ä»¶ã§ãã äŸïŒ
match(1, 2, 3)()
ãã®ãã³ãã¬ãŒãã¯ãçŸåšã®ãããã¯ã
link
ãããã¯ã§ãããã
this.ctx
ã®ã³ã³ããã¹ãã«
url
倿°ããããã©ãããããã³çŸåšã®ã¢ãŒãã
tag
modã§ãããã©ããã
this.ctx
ãŸãã ãããã®ãã¹ãŠã®æ¡ä»¶ãæºãããããšãã¿ã°ããããã¯ã«é©çšãããŸãã
ãã¡ãã·ã§ã³
ãã¡ãã·ã§ã³ã¯ãHTMLåºåãçæããã¹ãããã§ãã åmodã¯ãçµæã®HTMLã³ãŒãã®ç¬èªã®éšåãæ
åœããŸãã
default
ã¢ãŒãã¯ãæ®ãã®ã¢ãŒãã®ééã®ã»ãããšé åºãèšè¿°ããŸãã ãã®å³ã¯ãåã¢ãŒãã®åœ¹å²ã瀺ããŠããŸãã
BEMHTMLãã³ãã¬ãŒããšã³ãžã³ãªãã¡ã¬ã³ã¹ã¬ã€ãã«èšèŒãããŠããBEMHTMLããã¥ã¡ã³ããæ³šææ·±ãèªãããšããå§ãããŸãã
ãããžã§ã¯ãã«æ»ããŸãããã
form
ãããã¯ãå¿
èŠã§ãã
<form>
ãšããŠè¡šç€ºããã
JavaScript
å®è£
ãå¿
èŠã§ãã
ãã®ãããªãããã¯ãããŒãžã«ãã1ã€è¿œå ããå ŽåãBEMJSONãã¡ã€ã«ã§ãããã®ãã©ã¡ãŒã¿ãŒãçŽæ¥ç·šéããå¿
èŠããããŸãã ããã¯ãHTMLã§ã®ã€ã³ã©ã€ã³ã¹ã¿ã€ã«ã®äœ¿çšã«äŒŒãŠããŸãã ãã¹ãŠãæ£ããè¡ãããããã¯ãã©ã¡ãŒã¿ãŒããã³ãã¬ãŒãã«å
¥ããŸãããã
./desktop.blocks/form/form.bemhtml
ïŒ
block('form')( tag()('form'), js()(true) )
ããã§ããããã¯ãã³ãã¬ãŒãã1ãæã§ç·šéãããã®ãããã¯ãç°¡åã«è»¢éããŠåå©çšã§ããŸãã
ã€ã³ã¹ãã¯ã¿ãŒã§DOMããªãŒãèŠãŠã¿ãŸããã-
form
ãããã¯ã¯ã
i-bem
ã¯ã©ã¹ã®
<form>
ãšããŠè¡šç€ºãããããã«ãªããŸããã ãã®ã¯ã©ã¹ã¯ããããã¯ã«JavaScriptã®å®è£
ãããããšã瀺ããŠããŸãã

BEMãããã¯ãHTMLã«å€æããæ¹æ³ã«ã€ããŠèª¬æããŸããã ããã§ã¯ãtwitterããŒã¿ãã©ã®ããã«åä¿¡ãããåŠçãããããèŠãŠã¿ãŸãããã
ã¢ããªã±ãŒã·ã§ã³ã¢ãŒããã¯ãã£
2段éã®æšæºå
ã¢ããªã±ãŒã·ã§ã³ã¯æ¬¡ã®ããã«æ©èœããŸãã
- æåã®æ®µéã§ã¯ããµãŒãã¹ããããŒã¿ãåéãããã®ããŒã¿ã«åºã¥ããŠBEMããªãŒãæ§ç¯ããŸãã
- 2çªç®ã§ã¯ãBEMããªãŒïŒãã¥ãŒæåããŒã¿ïŒãDOMããªãŒã«å€æããHTMLãã¯ã©ã€ã¢ã³ãåŽã«ã¬ã³ããªã³ã°ããŸãã
ãã³ãã¬ãŒ
BEMããªãŒãHTMLã«å€æããæ¹æ³ã«ã€ããŠèª¬æããŸããã ããã¯ããã³ããšã³ããµãŒããŒã®ã¿ã¹ã¯ã§ãã ãŸããBEMTREEãã³ãã¬ãŒããšã³ãžã³ã¯ãBEMããªãŒãæ§ç¯ããŠããŒã¿ã§é£œåãããã¿ã¹ã¯ãåŠçããŸãã BEMHTMLãšåãæ§æã§ãã äž»ãªéãã¯ãå©çšå¯èœãªæšæºmodã®æ°ã§ãã BEMTREEã«ã¯ã
default
ãš
content
ã®ã¿ããã
default
ã
BEMTREEãžã®å
¥åã¯ããããã¯ãã³ãã¬ãŒãã飜åããŠããçããŒã¿ã§ãã åºåã§ã¯ãBEMããªãŒã®æ¢è£œã®ãã©ã°ã¡ã³ããååŸããBEMHTMLãã³ãã¬ãŒãã«æž¡ããŸãã
æŠãã«çŽè¡ããŸãã
{ type: 'twitter' }
修食åã
island
ãããã¯ã®BEMTREEãã³ãã¬ãŒããæžããŸãããïŒ
desktop.blocks/island/_type/island_type_twitter.bemtree
block('island').mod('type', 'twitter').content()(function() { var data = { postLink: '#', userName: 'user@name', userNick: 'user@nick', createdAt: '19 of July', avatar: '#avatar', text: 'message going here', type: 'twitter' }; return [ { elem: 'header', content: { block: 'user', content: [ { block: 'link', mods: { theme: 'islands' }, mix: { block: 'user', elem: 'name' }, url: data.postLink, content: [data.userName, ' @', data.userNick] }, { elem: 'post-time', content: data.createdAt.toString() }, { block: 'image', mix: { block: 'user', elem: 'icon' }, url: data.avatar, alt: data.userName } ] } }, { elem: 'text', content: data.text }, { elem: 'footer', content: [ { block: 'service', mods: { type: data.type } } ] } ]; });
ãã®ãããã¯ã®ã³ã³ãã³ãã«å¿
èŠãªãã©ã¡ãŒã¿ãŒãæå®ããŠ
image
ãããã¯ã転éãã
island
ãããã¯ã®
image
èŠçŽ ãæ··åããŸãã
å°æ¥ãéçãªããžã§ã¯ãããã³ãã¬ãŒãã«æž¡ãããããŒã¿ã«çœ®ãæããŸãã ããããæåã«ããµãŒããŒã³ãŒãã®ç·šææ¹æ³ãšããã®ããŒã¿ã®éä¿¡æ¹æ³ãèŠãŠã¿ãŸãããã
ãµãŒããŒäž
ãã®ã¢ããªã±ãŒã·ã§ã³ã¯ã
ãšã¯ã¹ãã¬ã¹ãã¬ãŒã ã¯ãŒã¯ã§åäœããŸã-æ€çŽ¢ã¯ãšãªã«å¿çããŠHTMLãã¬ã³ããªã³ã°ããŸãã
ãµãŒãã¹ããããŒã¿ãåéãããããã¯ãäœæããŸãã
*.node.js
æã€ãã¡ã€ã«ã«ãµãŒããŒã³ãŒããèšè¿°ããŸããããã¯ãã¢ã»ã³ããªäžã«1ã€ã®ãã¡ã€ã«ã«æ¥çãããŸãã
node.js
ã䜿çšããŠèµ·åã
node.js
service_type_twitter
ãããã¯
twitterã§ã®äœæ¥ãç°¡åã«ããããã«ã
twitã¢ãžã¥ãŒã«ã䜿çšããŸãã
npm
ã䜿çšããŠã€ã³ã¹ããŒã«ããŸãã
> npm i twit
twitterã§ã®äœæ¥ã«å¿
èŠãªèªèšŒããŒã¿ã¯ã
å¥ã®ãã¡ã€ã«ã«å
¥ã
ãŸã ã åãååã®ãã¡ã€ã«ã§ãã®å
容ãèªåèªèº«ã«ã³ããŒããŸãã
./desktop.blocks/service/_type/service_type_twitter.node.js
ç·šéã
./desktop.blocks/service/_type/service_type_twitter.node.js
ã
var twitter = require('twit'), config = require('./service_type_twitter.config'), twit = new twitter(config); var query = '#b_', results = []; twit.get('search/tweets', { q: query, count: 20 }, function(err, res) { if (err) { console.error(err); return []; } results = res.statuses.map(function(status) { var user = status.user; return { avatar: user.profile_image_url, userName: user.name, userNick: user.screen_name, postLink: 'https://twitter.com/' + user.screen_name, createdAt: status.created_at, text: status.text, type: 'twitter' }; }); console.log(results); });
ãã®ã¢ããªã±ãŒã·ã§ã³ã¯ãããŒã¯ãŒã
#b_
ãæ€çŽ¢ããçµæãã³ã³ãœãŒã«ã«è¡šç€ºããŸãã
ãããžã§ã¯ããåæ§ç¯ãã
node.js
ã䜿çšããŠå®è¡ããŸã
> enb make > node ./desktop.bundles/index/index.node.js
å®è¡ã®çµæã¯ãã³ã³ãœãŒã«ã®ãã€ãŒãã®ãªã¹ãã«ãªããŸãã
ããã§ããããªãäœæ¥ã®ããã«ãå®è¡ã®çµæãäœããã®æ¹æ³ã§è»¢éããå¿
èŠããããŸã-æšæºåãšã¯ã©ã€ã¢ã³ããžã®è»¢éã
promiseã䜿çšããéåæäœæ¥ã«ã¯ã
vowã©ã€ãã©ãªã䜿çšããŸãã
ãµãŒããŒãšã¯ã©ã€ã¢ã³ãã®JSã³ãŒãã®æ§æ-ã¢ãžã¥ã©ãŒã·ã¹ãã
YModules ã
ã¢ãžã¥ã©ãŒã·ã¹ãã
bem-core
ã©ã€ãã©ãªã¯ãã¢ãžã¥ã©ãŒã·ã¹ãã
ymodulesã䜿çšããŸãã
ãããã¯ã®ã³ãŒããã¢ãžã¥ãŒã«ã©ãããŒã«ã©ããããå¿
èŠã«å¿ããŠä»ã®ã¢ãžã¥ãŒã«ããåŒã³åºãããšãã§ããŸãã
次ã®è¿œå ã«åŸã£ãŠ
service_type_twitter.node.js
ãã¡ã€ã«ãç·šéããŸãã
modules.define('twitter', function(provide) { var vow = require('vow'), moment = require('moment'), twitter = require('twit'), twitterText = require('twitter-text'), config = require('./service_type_twitter.config'), twit = new twitter(config); provide({ get: function(query) { var dfd = vow.defer(); twit.get('search/tweets', { q: query, count: 20 }, function(err, res) { if(err || !res.statuses) { console.error(err); dfd.resolve([]); } dfd.resolve(res.statuses.map(function(status) { return { avatar: status.user.profile_image_url, userName: status.user.name, userNick: status.user.screen_name, postLink: 'https://twitter.com/' + status.user.screen_name, createdAt: moment(status.created_at), text: twitterText.autoLink(twitterText.htmlEscape(status.text)), type: 'twitter' }; })); }); return dfd.promise(); } }); });
ã芧ã®ãšããããã¹ãŠã®ã³ãŒãã
modules.define
ã³ã³ã¹ãã©ã¯ãã«ã©ããããŸããã ããã¯
twitter
ã¢ãžã¥ãŒã«å®£èšã§ããã
modules
åå空éãä»ããŠã¢ããªã±ãŒã·ã§ã³ã§åŸã§å©çšå¯èœã«ãªããŸãã
çµæã®éåæè»¢éã§ã¯ãã¯ãšãªã®çµæã«å¿ããŠããšã©ãŒãçºçããå Žåã¯ç©ºã®é
åããŸãã¯æ€çŽ¢çµæã®é
åãæž¡ããããã¹ãè¿ããŸãã
æ¥ä»ãåŠçããã«ã¯ãã¢ãžã¥ãŒã«
moment.js
远å ããŸãã
Twitterã¯ã¡ãã»ãŒãžã§ãã¬ãŒã³ããã¹ããè¿ãããã
twitter-text
ã©ã€ãã©ãªã䜿çšããŠããã·ã¥ã¿ã°ãšãªã³ã¯ã匷調衚瀺ããŸãã
ããã«ãäžèšã®ããã«ã
express
ãå¿
èŠã«ãªããŸãã
ãããã®ã¢ãžã¥ãŒã«ãã€ã³ã¹ããŒã«ããŸãããã
> npm i vow moment twitter-text express
server
ãããã¯
ãµãŒããŒãããã¯ã¯ãã¢ããªã±ãŒã·ã§ã³ã®ãµãŒããŒåŽã®æäœãæ
åœããŸãã ãã©ã«ããŒ
./desktop.blocks/server/
ã远å ãããã®äžã«
server.node.js
ãã¡ã€ã«ãäœæããŸãã
ããã¯ãURL
/search
ããªãã¹ã³ããèŠæ±ã«å¿ããŠããŒã¿ãè¿ã
express
ã¢ããªã±ãŒã·ã§ã³ã«ãªããŸãã
modules.require(['twitter'], function(twitter) { var fs = require('fs'), PATH = require('path'), express = require('express'), app = express(), url = require('url'), querystring = require('querystring'), Vow = require('vow'); app.get('/search', function(req, res) { var dataEntries = [], searchObj = url.parse(req.url, true).query, queryString = querystring.escape(searchObj.query), servicesEnabled = []; searchObj.twitter && servicesEnabled.push(twitter.get(queryString)); Vow.all(servicesEnabled) .then(function(results) { res.end(JSON.stringify(results, null, 4)); }) .fail(function() { console.error(arguments); }); }); var server = app.listen(3000, function() { console.log('Listening on port %d', server.address().port); }); });
次ã®å
容ã§
./desktop.blocks/sssr/sssr.deps.js
ãã¡ã€ã«ãäœæããŸãã
({ shouldDeps: [ { block: 'server' }, { block: 'island', mods: { type: ['twitter'] }} ] })
ããã§ã¯ã
sssr
ãããã¯ã
server
ããããã«
type: 'twitter'
修食åãæã€
server
ãããã¯ãš
island
ãããã¯ãå¿
èŠã§ãããšè¿°ã¹ãŠã
server
ã
server
ãããã¯ã«å¿ããŠ
service_type_twitter
修食åã远å ã
server
ã ãããè¡ãã«ã¯ããã¡ã€ã«
./desktop.blocks/server/server.deps.js
äœæããŸãã
({ shouldDeps: [ { block: 'service', mods: { type: ['twitter'] } }, { block: 'sssr', } ] })
ããã§ãå¿
èŠãªãã¹ãŠã®ãããã¯ãã¢ã»ã³ããªã«åé¡ãããŸãã ãããžã§ã¯ããåæ§ç¯ãããµãŒããŒãèµ·åããŸãã
> enb make && node ./desktop.bundles/index/index.node.js
ã¢ãã¬ã¹
httpïŒ// localhostïŒ3000 / searchïŒQuery =ïŒ
23b_ïŒtwitter = onã§ãJSONããŒã¿ãªããžã§ã¯ããå«ãããŒãžãéãã
service_type_twitter
ãããã¯ãæäŸããŸãã

次ã«ãBEMTREEã䜿çšããŠããã®ããŒã¿ã®BEMJSONãžã®å€æã远å ããŸãã
server.node.js
ïŒ
modules.require(['twitter'], function(twitter) { var fs = require('fs'), PATH = require('path'), VM = require('vm'), express = require('express'), app = express(), url = require('url'), querystring = require('querystring'), moment = require('moment'), Vow = require('vow'), pathToBundle = PATH.join('.', 'desktop.bundles', 'index'); app.use(express.static(pathToBundle)); var bemtreeTemplate = fs.readFileSync(PATH.join(pathToBundle, 'index.bemtree.js'), 'utf-8'); var context = VM.createContext({ console: console, Vow: Vow }); VM.runInContext(bemtreeTemplate, context); var BEMTREE = context.BEMTREE; app.get('/search', function(req, res) { var dataEntries = [], searchObj = url.parse(req.url, true).query, queryString = querystring.escape(searchObj.query), servicesEnabled = []; searchObj.twitter && servicesEnabled.push(twitter.get(queryString)); Vow.all(servicesEnabled) .then(function(results) { // , // Object.keys(results).map(function(idx) { dataEntries = dataEntries.concat(results[idx]); }); // dataEntries.sort(function(a, b) { return b.createdAt.valueOf() - a.createdAt.valueOf(); }); // BEMJSON BEMTREE BEMTREE.apply(dataEntries.map(function(dataEntry) { dataEntry.createdAt = moment(dataEntry.createdAt).fromNow(); return { block: 'island', data: dataEntry, mods: { type: dataEntry.type } }; })) .then(function(bemjson) { // JSON res.end(JSON.stringify(bemjson, null, 4)); }); }) .fail(function() { console.error(arguments); }); }); var server = app.listen(3000, function() { console.log('Listening on port %d', server.address().port); }); });
BEMTREE- ,
vow
, .
, , .
BEMTREE.apply()
, , - , BEMTREE-.
./desktop.blocks/island/_type/island_type_twitter.bemtree
:
block('island').mod('type', 'twitter').content()(function() { var data = this.ctx.data; return [
this.ctx.data
,
BEMTREE.apply()
.
http://localhost:3000/search?query=%23b_&twitter=on . BEMJSON, BEMTREE.
BEMJSON HTML
BEMHTML.apply()
. server.node.js :
var BEMHTML = require(PATH.join('../../' + pathToBundle, 'index.bemhtml.js')).BEMHTML; //⊠BEMTREE.apply(dataEntries.map(function(dataEntry) { dataEntry.createdAt = moment(dataEntry.createdAt).fromNow(); return { block: 'island', data: dataEntry, mods: { type: dataEntry.type } }; })) .then(function(bemjson) { if (searchObj.json) { return res.end(JSON.stringify(bemjson, null, 4)); } res.end(BEMHTML.apply(bemjson)); }); //âŠ
, HTML, â AJAX.
json=on
â BEMJSON- â
http://localhost:3000/search?query=%23b_&twitter=on&json=on .

JavaScript i-bem.js
JavaScript JavaScript- - - â
i-bem.js
.
bem-core
.
i-bem.js
â
i-bem
js
.
jQuery
API .
, i-bem.js
.
:
js-
js-, . , , js-, BEMHTML
js
, BEMJSON â
js
:
// bemhtml block('form').js()(true);
// bemjson { block: 'form', js: true }
// bemjson with js params { block: 'form', js: { p1: 'v1', p2: 'v2' } }
js
, , js- . HTML:
<div class="form i-bem" data-bem="{form: {p1: 'v1', p2 : 'v2'}}"></div>
i-bem
, DOM- js-. -
data-bem
, js-, â , .
js
form
./desktop.blocks/form/form.js
:
modules.define('form', ['i-bem__dom'], function(provide, BEMDOM) { provide(BEMDOM.decl(this.name, { onSetMod: { js: { inited: function() { this.bindTo('submit', this._onSubmit); } } }, _onSubmit: function(e) { e.preventDefault(); this.emit('submit'); }, getVal: function() { return this.domElem.serialize(); } })); });
bem-core
.
i-bem
â .
i-bem__dom
â , DOM .
form
,
i-bem__dom
, DOM-.
BEMDOM
.
form
. ,
js
inited
â
i-bem.js
. ,
_onSubmit
, ,
getVal
, .
_onSubmit()
e.preventDefault()
, -
submit
, . API
form
. -.
sssr
, .
./desktop.blocks/sssr/sssr.js
:
modules.define('sssr', ['i-bem__dom', 'jquery'], function(provide, BEMDOM, $) { provide(BEMDOM.decl(this.name, { onSetMod: { js: { inited: function() { this.findBlockInside('form').on('submit', this._sendRequest, this); } } }, _sendRequest: function() { $.ajax({ type: 'GET', dataType: 'html', cache: false, url: '/search/', data: this.findBlockInside('form').getVal(), success: this._onSuccess.bind(this) }); }, _onSuccess: function(html) { BEMDOM.update(this.elem('content'), html); } })); });
.
sssr
i-bem__dom
, DOM-,
jquery
AJAX.
submit
form
.
_sendRequest
, AJAX-. ,
_onSuccess
,
sssr__content
.
,
i-bem.js
,
sssr
js-:
// desktop.blocks/sssr/sssr.bemhtml block('sssr').js()(true);
, , .
index.node.js
:
$ enb make && node ./desktop.bundles/index/index.node.js
.
localhost:3000 , - , . , .

, .
borschik
.
.borschik
:
{ "freeze_paths": { "libs/**": ":base64:", "libs/**": ":encodeURIComponent:" } }
production
:
> YENV=production enb make && node desktop.bundles/index/index.node.js
.

. spin
- , . , «».
spin
, . BEMJSON-.
bem-components
API. :
modules.require(['jquery'], function($) { $('.spin').bem('spin').setMod('visible'); });

spin_visible
true
.
,
js
- .
./desktop.blocks/sssr/sssr.styl
:
.sssr { .spin { margin-left: 1em; vertical-align: middle; } }
, .
./desktop.blocks/sssr/sssr.js
:
modules.define('sssr', ['i-bem__dom', 'jquery'], function(provide, BEMDOM, $) { provide(BEMDOM.decl(this.name, { onSetMod: { js: { inited: function() { this.findBlockInside('form').on('submit', this._doRequest, this); } }, loading: function(modName, modVal) { console.log('visible: ', modVal); this.findBlockInside('spin').setMod('visible', modVal); } }, // ⊠_doRequest: function() { this.setMod('loading'); this._sendRequest(); }, _onSuccess: function(html) { this.delMod('loading'); BEMDOM.update(this.elem('content'), html); } })) })
JS-, CSS- . , , .
./desktop.bundles/sssr/sssr.styl
:
.sssr { .spin { margin-left: 1em; vertical-align: middle; } &_loading .content { opacity: 0.5; } }
:
localhost:3000 .
spin
, â .

, , .
isEmpty()
:
./desktop.blocks/form/form.js
:
isEmpty: function() { return !this.findBlockInside('input').getVal().trim() || this.findBlocksInside('checkbox').every(function(checkbox) { return !checkbox.hasMod('checked'); }); }
input
checkbox_checked
.
, ,
sssr
:
./desktop.blocks/sssr/sssr.js
:
modules.define('sssr', ['i-bem__dom', 'jquery'], function(provide, BEMDOM, $) { provide(BEMDOM.decl(this.name, { onSetMod: { js: { inited: function() { this.findBlockInside('form').on('submit', this._doRequest, this); } }, loading: function(modName, modVal) { this.findBlockInside('spin').setMod('visible', modVal); } }, _doRequest: function() { if (this.findBlockInside('form').isEmpty()) { return; } this.setMod('loading'); this._sendRequest(); }, _sendRequest: function() {
_doRequest()
.
, , .
_sendRequest()
clear()
_updateContent()
.
./desktop.blocks/sssr/sssr.js
:
modules.define('sssr', ['i-bem__dom', 'jquery'], function(provide, BEMDOM, $) { provide(BEMDOM.decl(this.name, { onSetMod: { js: { inited: function() { this.findBlockInside('form').on('submit', this._doRequest, this); } }, loading: function(modName, modVal) { this.findBlockInside('spin').setMod('visible', modVal); } }, _doRequest: function() { if (this.findBlockInside('form').isEmpty()) { return; } this.setMod('loading'); this._sendRequest(); }, clear: function() { this._xhr && this._xhr.abort(); this._updateContent(''); this.delMod('loading'); }, _sendRequest: function() { this._xhr && this._xhr.abort(); this._xhr = $.ajax({ type: 'GET', dataType: 'html', cache: false, url: '/search/', data: this.findBlockInside('form').getVal(), success: this._onSuccess.bind(this) }); }, _onSuccess: function(result) { this.delMod('loading'); this._updateContent(result); }, _updateContent: function(html) { BEMDOM.update(this.elem('content'), html); } })); })
, ,
.
form
change
input
:
modules.define('form', ['i-bem__dom'], function(provide, BEMDOM) { provide(BEMDOM.decl(this.name, { onSetMod: { js: { inited: function() { this.bindTo('submit', this._onSubmit); this.findBlockInside('input').on('change', this._onChange, this); } } }, _onChange: function() { this.emit('change'); },
change
sssr
,
./desktop.blocks/sssr.js
:
modules.define('sssr', ['i-bem__dom', 'jquery'], function(provide, BEMDOM, $) { provide(BEMDOM.decl(this.name, { onSetMod: { js: { inited: function() { this.findBlockInside('form').on('submit change', this._doRequest, this); } },
,
./desktop.blocks/form.js
:
modules.define('form', ['i-bem__dom'], function(provide, BEMDOM) { provide(BEMDOM.decl(this.name, { onSetMod: { js: { inited: function() { this.bindTo('submit', this._onSubmit); this.findBlockInside('input').on('change', this._onChange, this); BEMDOM.blocks.checkbox.on(this.domElem, 'change', this._onChange, this); } } },
:

. .
debounce
bem-core
.
sssr
sssr.deps.js
:
({ shouldDeps: [ { block: 'server' }, { block: 'island', mods: { type: ['twitter'] }}, { block: 'functions', elem: 'debounce' } ] })
- . ,
functions__debounce
debounce
:
modules.define('sssr', ['i-bem__dom', 'jquery', 'functions__debounce'], function(provide, BEMDOM, $, debounce) { provide(BEMDOM.decl(this.name, { onSetMod: { js: { inited: function() { this.findBlockInside('form').on('submit change', this._doRequest, this); this._debounceRequest = debounce(this._sendRequest, 500, this); } }, loading: function(modName, modVal) { this.findBlockInside('spin').setMod('visible', modVal); } }, _doRequest: function(e) { this.setMod('loading'); if (this.findBlockInside('form').isEmpty()) { this._clear(); return; } e.type === 'change' ? this._debounceRequest(): this._sendRequest(); }, _clear: function() { this._xhr && this._xhr.abort(); this._updateContent(''); this.delMod('loading'); }, _sendRequest: function() { this._xhr && this._xhr.abort(); this._xhr = $.ajax({ type: 'GET', dataType: 'html', cache: false, url: '/search/', data: this.findBlockInside('form').getVal(), success: this._onSuccess.bind(this) }); }, _onSuccess: function(result) { this.delMod('loading'); this._updateContent(result); }, _updateContent: function(html) { BEMDOM.update(this.elem('content'), html); } })); });
, . â .
.
sssr
params
.
index.bemjson.js
:
{ block: 'sssr', mods: { autorefresh: true }, js: { url: '/search/', refreshInterval: 10000 },
:
./desktop.blocks/sssr/_autorefresh/sssr_autorefresh.js
:
modules.define('sssr', ['tick'], function(provide, tick, Sssr) { provide(Sssr.decl({ modName: 'autorefresh' }, { onSetMod: { loading: function(modName, modVal) { // this.__base.apply(this, arguments); // â , // â modVal ? this._clearTimer(): this._setTimer(); } }, _setTimer: function() { this._counter = 0; tick.on('tick', this._onTick, this); }, _onTick: function() { // (++this._counter * 50) % this.params.refreshInterval || this._sendRequest(); }, _clearTimer: function() { tick.un('tick', this._onTick, this); }, getDefaultParams: function() { return { refreshInterval: 10000 }; } })); });
this.__base
sssr_loading
.
tick
.
tick
50 .
sssr_loading
, , .
refreshInterval
sssr
, .
getDefaultParams
. , .
sssr
.
desktop.blocks/sssr/sssr.deps.js
:
({ shouldDeps: [ 'server', { block: 'functions', elem: 'debounce' }, { block: 'island', mods: { type: ['twitter'] } } ] })
. 10 .
, ,
.
this.findBlockInside('form')
this._form
.
spin
.
sssr
, .
modules.define('sssr', ['i-bem__dom', 'jquery', 'functions__debounce'], function(provide, BEMDOM, $, debounce) { provide(BEMDOM.decl(this.name, { onSetMod: { js: { inited: function() { this._spin = this.findBlockInside('spin'); this._form = this.findBlockInside('form') .on('submit', this._doRequest, this); this._debounceRequest = debounce(this._sendRequest, 500, this); } }, loading: function(modName, modVal) { this._spin.setMod('visible', modVal); } }, _doRequest: function(e) { this.setMod('loading'); if (this._form.isEmpty()) { this._clear(); return; } e.type === 'change' ? this._debounceRequest(): this._sendRequest(); }, _clear: function() { this._abortRequest(); this._updateContent(''); this.delMod('loading'); }, _abortRequest: function() { this._xhr && this._xhr.abort(); }, _sendRequest: function() { this._abortRequest(); this._xhr = $.ajax({ type: 'GET', dataType: 'html', cache: false, url: this.params.url, data: this._form.getVal(), success: this._onSuccess.bind(this) }); }, _onSuccess: function(result) { this.delMod('loading'); this._updateContent(result); }, _updateContent: function(result) { BEMDOM.update(this.elem('content'), result); } })); });
, , ,
_abortRequest()
.
é
å»¶åæå
, , .
.
live
-.
i-bem.js .
sssr
form
, . :
./desktop.blocks/sssr/sssr.js
:
modules.define('sssr', ['i-bem__dom', 'jquery', 'functions__debounce'], function(provide, BEMDOM, $, debounce) { provide(BEMDOM.decl(this.name, { onSetMod: { js: { inited: function() { this._form = this.findBlockInside('form'); this._spin = this.findBlockInside('spin'); this._debounceRequest = debounce(this._sendRequest, 500, this); } }, loading: function(modName, modVal) { this._spin.setMod('visible', modVal); } }, _clear: function() { this._abortRequest(); this._updateContent(''); this.delMod('loading'); }, _doRequest: function(needDebounce) { if (this._form.isEmpty()) { this._clear(); return; } this.setMod('loading'); needDebounce? this._debounceRequest() : this._sendRequest(); }, _sendRequest: function() { this._abortRequest(); this._xhr = $.ajax({ type: 'GET', dataType: 'html', url: this.params.url, data: this._form.getVal(), cache: false, success: this._onSuccess.bind(this) }); }, _abortRequest: function() { this._xhr && this._xhr.abort(); }, _onSuccess: function(result) { this._updateContent(result); this.delMod('loading'); }, _updateContent: function(html) { BEMDOM.update(this.elem('content'), html); } }, { live: function() { this.liveInitOnBlockInsideEvent('submit change', 'form', function(e) { this._doRequest(e.type === 'change'); }); } })); });
live
-
form
:
./desktop.blocks/form/form.js
:
modules.define('form', ['i-bem__dom'], function(provide, BEMDOM) { provide(BEMDOM.decl(this.name, { onSetMod: { js: { inited: function() { this._input = this.findBlockInside('input'); this._checkboxes = this.findBlocksInside('checkbox'); } } }, // ⊠isEmpty: function() { return !this._input.getVal().trim() || this._checkboxes.every(function(checkbox) { return !checkbox.hasMod('checked'); }); } }, { live: function() { var ptp = this.prototype; this .liveBindTo('submit', ptp._onSubmit) .liveInitOnBlockInsideEvent('change', 'input', ptp._onChange) .liveInitOnBlockInsideEvent('change', 'checkbox', ptp._onChange); } })); });
input
checkbox
, ,
findBlockInside
.
, -.
i-bem.js
, BEMTREE - BEMHTML - HTML.
sssr service__type__*
API Instagram .. , . , .
, .
info@bem.info .