Open Drekrosh opened 9 years ago
@Rahnar что именно подразумевается под динамикой?
Ну , например из json дергать инфу , использовать его как некую такую базу данных. Либо как - то так, чтобы я не расписывал колбасу из 10 штук , написал один раз нужную вложенность, начиная с блока меню , соотвественно его элемент один li , который был бы описан динамически , а на выходе я получил уже собранное меню из 10 шт. Или вообще нет смысла от этих манипуляций ?? Как Вы друзья из Яндекс, описываете подобные вещи? Извините за идиотские вопросы , щас уровень наберу и все будет ок)
@Rahnar Похоже, все равно получается 3 варианта ответа :)
BEMJSON — это JavaScript и можно смело пользоваться такими конструкциями:
{
block: 'menu',
content: [
{ title: 'Заголовок 1', url: 'http://site1.com/' },
{ title: 'Заголовок 2', url: 'http://site2.com/' },
{ title: 'Заголовок 3', url: 'http://site3.com/' }
].map(function(item) {
return {
elem: 'item',
content: {
block: 'link',
url: item.url,
content: item.content
}
};
})
}
Очевидно, что это по-прежнему будет статика, мы просто избавляемся от колбасы средствами JS прямо в статичном bemjson.js-файле.
Можно унести все в шаблон. bemjson.js:
{
block: 'menu',
content: [
{ title: 'Заголовок 1', url: 'http://site1.com/' },
{ title: 'Заголовок 2', url: 'http://site2.com/' },
{ title: 'Заголовок 3', url: 'http://site3.com/' }
]
}
bemhtml:
block('menu').content()(function() {
return applyNext().map(function(item) {
return {
elem: 'item',
content: {
block: 'link',
url: item.url,
content: item.content
}
};
});
});
build.js
var data = require('db.json'),
BEMHTML = require('./desktop.bundles/index/index.bemhtml.js').BEMHTML;
console.log(BEMHTML.apply({
block: 'menu',
content: data.map(function(item) {
return {
elem: 'item',
content: {
block: 'link',
url: item.url,
content: item.content
}
};
})
})); // вернется HTML-строка
Это, конечно, неудобно. Код я привел, чтобы было понятно, что там происходит под капотом.
bem-tools
есть коммит про поддержку require
прямо в bemjson.js-файлах.Можно склонировать ее в node_modules, сказать там npm link
и пользоваться bem server
для сборки. Это уже удобнее, но придется пользоваться пока еще невыпущенной версией сборщика.
Если коротко, то схема предполагает 2 этапа шаблонизации:
Пример готовой настройки для ENB можно взять тут https://github.com/tadatuta/bem-bemtree-static-project-stub
Отличия от официального project-stub
видны в этом коммите:
Важное отличие от подхода из project-stub
: теперь декларацией для сборки служит не bemjson.js
, а bemdecl.js
, т.к. bemjson.js
генерируется на основе BEMTREE-шаблонов динамически в процессе сборки.
В данном конкретном случае точкой входа служит блок root
. Все остальные блоки попадают в сборку по зависимостям.
В результате это по-прежнему статическая генерация HTML, но уже двухпроходная, что избавляет от написания колбасы руками.
Здесь работает тот же принцип двухпроходности, но вместо того, чтобы описывать каждую страницу заранее, используется сервер, который будет отдавать разные данные в зависимости от урла и прочих пользовательских настроек.
Я обязательно напишу про этот пункт отдельный подробный пост и сделаю демо-репозиторий. А пока рекомендую посмотреть https://github.com/bem/sssr и сопровождающее видео с BEMUp-а.
@tadatuta сейчас возникла таже необходимость :)
Из перечисленного делаю 2-ым способом, но больше всех нравится 3.2 (т.к. для 2-го варианта необходимо "чистить" входные данные, чтобы визуально они не засоряли bemjson)
Ого!!Спасибо огромное , Владимир! Очень все доходчиво! И вот такой вопрос еще, начал изучать фреймверк i-bem.js , все никак не пойму, он полностью заменяет нативный javascript, тобишь мы пишем на нем используя ваш синтаксис и ООП. Он позволяет решать небольшие задачи , типа слайдер написать? И можно ли обходиться без него?Хотя , я намерен его использовать ,просто хочу понять диапазон его применения.Или на нем можно сделать все то, что можно сделать на жуке(jquery)?
@tadatuta а можно использовать переменные? Допустим у меня данные дублируются, но используются в разных блоках по разному. Как это будет выглядить в bemjson?
@Rahnar i-bem.js - это вполне себе нативный js. Да, он позволяет решать небольшие задачи, "типа слайдер написать". Вот вам пример карусели. Под капотом у i-bem jquery, так что да, на нем можно сделать все то, что можно сделать на jquery.
@Rahnar Хорошими примерами компонентов на i-bem.js могут служить блоки из bem-components.
По поводу i-bem.js и jQuery: у i-bem-блоков есть поле domElem
, которое является указателем на jQuery-chain данного блока. Т.е. this.domElem в i-bem-блоке button
— это то же самое, что $('.button').eq(0)
. Кроме того все элементы представлены jquery-коллекциями (this.elem('control') == $('.button__control')
).
Можно сказать, что i-bem.js добавляет к jQuery возможность декларативно описывать компоненты и предоставляет хелперы для работы с предметной областью БЭМ (проверить, установить или поменять модификаторы, найти элементы и т.п.).
@belozyorcev
а можно использовать переменные?
Вот прямо совсем как в любом JS-файле ;) Ну, например,
(function() {
var ololo = [1, 2, 3];
return {
block : 'page',
title : 'Title of the page',
favicon : '/favicon.ico',
head : [
{ elem : 'css', url : '_index.css' }
],
scripts: [{ elem : 'js', url : '_index.js' }],
mods : { theme : 'islands' },
content : ololo[2]
};
})()
@tadatuta это именно в bemjson ? Или в шаблонах? В bemhtml я свободно пользуюсь, а вот задать где-то глобально в bemjson не пойму как
@belozyorcev В bemjson. Можно вот прямо так целиком скопировать сниппет, который я привел выше, он будет работать ;)
bemjson.js-файл
в project-stub
просто эвалится в пустом контексте (vm.runInNewContext()
) и результат отдается в BEMHTML.apply()
. Т.е. важно, чтобы в результате выполнения bemjson.js вернулась строка или js-объект, а внутри может быть произвольный JS-код.
PS: ENB для выполнения bemjson.js-файлов использует метод requireOrEval
, что означает, что в bemjson-файлах можно использовать require
уже сейчас, если экспортировать их как common.js-модули:
index.bemjson.js:
var bemjson = {
block: 'page'
};
bemjson.content = require('./data.json');
module.exports = bemjson;
Я тоже сейчас пилю двухуровневое меню на базе bem-components. Надеюсь через неделю выложить на общий суд и собрать фидбек.
По-моему, самый простой и верный способ собирать такое меню в bemtree шаблоне. Выглядеть будет примерно так:
block('header')(
content()(function() {
var menu = data.items.map(function(item) {
return {
block : 'menu-item',
mods: { type: 'link' },
url : item.url,
content : item.title
};
});
return [
{
elem : 'menu',
content : [
{
block : 'menu',
content : menu
}
]
}
];
})
);
@tadatuta - а путь require('./data.json')
относительно чего строится?
@tadatuta. С путём разобрался :) Относительно bemjson файла.
Вот другая задача. Делаю следующее
...
{
block: 'b-map-list-p',
js: true,
mix: [{block: 'b-map-filters', elem: 'profgroups'}],
mods: {theme: 'second'},
content: [
{
elem: 'inner',
list: (function() {
var content = require('../../json/profgroups.json');
module.exports = content;
})()
}
]
}
...
но получаю при перезагрузке браузера undefined
. Пока не знаю куда копать...
в list я должен получить массив элементов, которые затем обработать в bemtree/bemhtml
@belozyorcev Если я правильно угадываю, чего хочется добиться, то должно быть как-то так:
var bemjson = [
// ...
{
block: 'b-map-list-p',
js: true,
mix: [{block: 'b-map-filters', elem: 'profgroups'}],
mods: {theme: 'second'},
content: [
{
elem: 'inner',
list: require('../../json/profgroups.json')
}
]
}
// ...
];
module.exports = bemjson;
@tadatuta я не понимаю, куда это вставлять в bemjson файле? У нас же оно построенно как объект JS. Но тут у нас появляется переменная bemjson. У меня начинает путаница возникать в голове...
П.Н. Что делает это код понимаю, а вот как использовать этот код в bemjson файле нет.
@belozyorcev bemjson.js — это просто javascript-файл. все, что требуется — это чтобы в результате его выполнения экспортировалось дерево. а код может быть совершенно произвольным. поэтому то, что я привел выше — это и есть контент bemjson.js-файла. если начинать от page
, то он может выгядеть, допустим, так:
// cat desktop.bundles/index/index.bemjson.js
module.exports = {
block : 'page',
title : 'Title of the page',
favicon : '/favicon.ico',
head : [
{ elem : 'meta', attrs : { name : 'description', content : '' } },
{ elem : 'meta', attrs : { name : 'viewport', content : 'width=device-width, initial-scale=1' } },
{ elem : 'css', url : '_index.css' }
],
scripts: [{ elem : 'js', url : '_index.js' }],
mods : { theme : 'islands' },
content : {
block: 'b-map-list-p',
js: true,
mix: [{block: 'b-map-filters', elem: 'profgroups'}],
mods: {theme: 'second'},
content: [
{
elem: 'inner',
list: require('../../json/profgroups.json')
}
]
}
};
@tadatuta теперь в моей голове всё прояснилось и стало на свои места :) Спасибо, всё заработало :) Теперь bemjson файл похудеет раза в 3-4
После перевода на require
подход - размер bemjson уменьшился в 5 раз. Стало быстрее и проще ориентироваться в "чертеже" проекта
Делаю сейчас меню по такому принципу:
bemjson:
{
block: 'menu',
content: [
{ title: 'Главная', url: 'http://site1.com/' },
{ title: 'Услуги', url: 'http://site2.com/' },
{ title: 'Контакты', url: 'http://site3.com/' }
]
},
в бемхтмл кладу
block('menu').content()(function() {
return applyNext().map(function(item) {
return {
block: 'item',
content: {
block: 'link',
url: item.url,
content: item.title
}
};
});
});
выдает ошибку Cannot read property '0' of undefined а если засунть мой массив с title и url в сам bemhtml и сделать на него map, то он увидит содержимое массива...
Блок menu
из bem-components
поддерживает только menu-item
или menu__group
в свойствах content
@Guria тобишь так
block('menu').content()(function() {
return applyNext().map(function(item) {
return {
elem: 'menu-item',
content: {
block: 'link',
url: item.url,
content: item.title
}
};
});
});
Почти. menu-item
это отдельный блок: https://ru.bem.info/libs/bem-components/v2.0.0/desktop/menu-item/
PS. код можно оформлять с помощью github-flawored markdown
@Guria а почему может не работать блок link я обернул в нее блок image и он как тэг определился сам , а вот блок линк не хочет((
@Rahnar продемонстрируй код
@Rahnar Предположу, что не хватает зависимостей в deps.js
как правильно код вставить , красивый ? Я оборачиваю в тег <code>
чет не получается..
@tadatuta Вы правы Владимир, написал deps и все прекрасно увидел.
как правильно код вставить , красивый ? Я оборачиваю в тег
<code>
чет не получается..
Три бек-тика (`) и опционально слитно язык (например, js) в начале и просто три бек-тика в конце.
@tadatuta
block('social').content()(function() {
return applyNext().map(function(item) {
return {
elem: 'item',
content: {
block: 'link',
url: item.url,
content: {
block: "image",
url: item.img
}
}
};
});
});
Я написал вот такой вот код, все работает , deps написал для вложенных блоков в блок social. Но не видит теперь элемент item. Он его в коде рисует, но стили не могу к нему применить. Опять в deps дело?
@Rahnar думаю, да. общее правило: все сущности, которых нет в bemjson (если речь о статичной странице) и которые вынесены в отдельный файл на файловой системе, должны быть задекларированы в deps.js, чтобы сборщик знал, что их нужно собирать.
@tadatuta Я разобрался , короче все дело в том, что я то писал в social.deps.js где явно указал на елемент item , чтобы сборщик его видел. Но он по факту его не видел , я решил дать другое имя , не item а items и тут же все заработало. item- это что, зарезервированное имя какое-то?Почему он на него так реагирует. На любые другие имена , пожалуйста.
Вопрос снимается, все ответы на вопросы мною найдены и разобраны. Спасибо за терпение и помощь!)
Так и не смог победить кэш require (bemjson). Пытаюсь разбить страницы на участки и динамично инклудить, но всё портит кэш. Победить вообще никак?
Победить вообще никак?
- Использовать https://github.com/gulp-bem/node-eval с
fs.readFileSync
ВМЕСТОrequire
.- Использовать https://github.com/sindresorhus/clear-require вместе с
require
, непосредственно ПЕРЕД.
Спасибо за наводку! буду пробовать )
Здравствуйте , у меня есть меню и там 10 списков li , как мне сделать так, чтобы я в бэм дереве его статически не описывал, а как то динамически вывести его. Хотя бы подсказку увидеть, в какую сторону мне двигаться чтобы этого добиться.