Войти с помощью github

Добрый вечер

Пытаюсь вывести данные из JSON, как сказано здесь - https://ru.bem.info/forum/716/

Ничего не выходит, помогите найти ошибку

Вывожу вот так - http://joxi.ru/V2VL9x3SxLX34r

Выдаёт ошибку TypeError: Cannot read property 'apply' of undefined http://joxi.ru/1A5xBqGsnO6Nd2

В переменную BEMTREE почему-то ничего не приходит.

Проверил в вышеобозначенном файле page.bemtree.js через console.log() значения этих четырёх переменных:

  • PATH
  • pathToBundle
  • BEMTREE
  • BEMHTML

Все имеют значение, кроме BEMTREE имеющей undefined

Сборку свою текущую загрузил сюда - https://yadi.sk/d/6WCDVmYN3MqEBL

Есть примерно следующая структура вложенных блоков:

{
    block : 'box',
    mods : {
        root : true,
        id : 'layoutBox',
    },
    content : {
        block : 'box',
        mods : {
            id : 'appBox',
        },
        // Имеем некоторую вложенность блоков `box`: layoutBox->appBox->ReportLayout->Report->ReportDisplay; Т.е.:
        // ...
        content : {
            block : 'ReportDisplay',
            mix : {
                block : 'box',
                mods : {
                    id : 'ReportDisplay',
                },
            },
            content : {
                // Some content...
            },
        },
    },
}

При удалении блока ReportDisplay (при помощи BEMDOM.destruct(ReportDisplay.domElem)) по цепочке parentNode (в jquery) до верхнего уровня (layoutBox) всплывает событие на delMod('js'), в результате чего блок отписывается от событий, зарегистрированных на window (ранее подписываемся так: this._domEvents(BEMDOM.win).on('resize',...)).

Стек выглядит примерно так:

    (i-bem-dom__events.js:155) this._storage[e] = null; // e='resize' -- Это собственно удаление подписанного события в _unbindByEvent.
    // ...
    (i-bem-dom__events.js:139) objects.each(this._storage, this._unbindByEvent, this); // this._storage={resize:{uniq161:{...}}}
    (i-bem-dom__events.js:253) params.bindToArbitraryDomElem && ctxStorage[storageKey] &&
                            ctxStorage[storageKey].un();
    (i-bem-dom__events_type_bem.js:85) fn.call(fnCtx || instance, originalEvent, data); // fnCtx=null, instance=layoutBox, originalEvent={bemTarget:ctx,data:undefined,target:ctx,type:'modchange'_isDefaultPrevented:false_isPropagationStopped:false}, data={modName:'js', modVal:'',oldModVal:'inited'}
    (jquery:5205) ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||     //  handleObj.origType='__bem__box_js_'
                        handleObj.handler ).apply( matched.elem, args ); //  matched.elem=layoutBox.domElem[0], args=[jQuery.Event{type:'__bem__box_js_'},{modName:'js', modVal:'',oldModVal:'inited'},{fns:{uniq151:true},propagationStoppedDomNode:null},{bemTarget:ctx,data:undefined,target:ctx,type:'modchange'_isDefaultPrevented:false_isPropagationStopped:false}]
    (jquery.js:5014) jQuery.event.dispatch.apply( elem, arguments ); // elem=layoutBox.domElem[0], ...
    (jquery:8201) handle.apply( cur, data ); // cur=layoutBox.domElem[0], data=[jQuery.Event{type:'__bem__box_js_'},{modName:'js', modVal:'',oldModVal:'inited'},{fns:{uniq151:true},propagationStoppedDomNode:null},{bemTarget:ctx,data:undefined,target:ctx,type:'modchange'_isDefaultPrevented:false_isPropagationStopped:false}]
    (jquery.js:8262) jQuery.event.trigger(type, data, this); // type='__bem__box_js_', data=[{modName:'js', modVal:'',oldModVal:'inited'},{fns:{uniq151:true},propagationStoppedDomNode:null},{bemTarget:ctx,data:undefined,target:ctx,type:'modchange'_isDefaultPrevented:false_isPropagationStopped:false}], this=ctx
    (jquery.js:8269) ctx.domElem.trigger(event, [data, { fns : {}, propagationStoppedDomNode : null }, originalEvent]); // event='__bem__box_js_', data={modName:'js',modVal:'',oldModVal:'inited'}, originalEvent:{bemTarget:ctx,data:undefined,target:ctx,type:'modchange'_isDefaultPrevented:false_isPropagationStopped:false}
    // ...
    (i-bem-dom.js:676) bemEvents.emit(this, e, data); // e={modName:'js',modVal:''}, data={modName:'js', modVal:'',oldModVal:'inited'}
    (i-bem-dom.js:733) this._emit({ modName : 'js', modVal : '' }, eventData); // eventData={modName:'js',modVal:'',oldModVal:'inited'}
    (i-bem.vanilla.js:324) this._afterSetMod('js', '', 'inited');
    (i-bem.vanilla.js:382) this.setMod('js', '');
    (i-bem.vanilla.js:247) this.delMod('js');
    (i-bem-dom.js:244) entity._delInitedMod();
    (i-bem-dom.js:1004) removeDomNodeFromEntity(entity, domNode);
    // ...
    (i-bem-dom.js:1029) this._destruct(ctx, excludeSelf, true);
    BEMDOM.destruct(ReportDisplay.domElem);

Полностью слепок вершины стека из DevTools, от destruct до _unbindByEvent).

_unbindByEvent (i-bem-dom__events.js:155)
each (objects.vanilla.js:56)
un (i-bem-dom__events.js:139)
(anonymous) (i-bem-dom__events.js:254)
inherit._createEventManager (i-bem-dom__events_type_bem.js:85)
dispatch (jquery.js:5206)
jQuery.event.add.elemData.handle (jquery.js:5014)
trigger (jquery.js:8201)
(anonymous) (jquery.js:8269)
each (jquery.js:362)
each (jquery.js:157)
trigger (jquery.js:8268)
emit (i-bem-dom__events_type_bem.js:119)
_emit (i-bem-dom.js:676)
_afterSetMod (i-bem-dom.js:733)
setMod (i-bem.vanilla.js:324)
delMod (i-bem.vanilla.js:382)
_delInitedMod (i-bem.vanilla.js:247)
removeDomNodeFromEntity (i-bem-dom.js:244)
(anonymous) (i-bem-dom.js:1004)
each (objects.vanilla.js:56)
(anonymous) (i-bem-dom.js:1000)
each (jquery.js:362)
each (jquery.js:157)
_destruct (i-bem-dom.js:993)
destruct (i-bem-dom.js:1029)

Т.е., раскрутить до конца я раскрутил, но вот дальше собственных мозгов разбраться, почему так происходит, как-то уже не хватает, увы. %((

Пока обхожусь принудительной переинициализацией событий на верхнем уровне после изменения содержимого.

Хелп? Что это может быть?

Версии библиотек:

  • bem-core@4.2.1
  • jquery@3.2.1

Добрый вечер

Использую project stub

Ранее всю разметку писал в index.bemjson.js, сейчас же решил оставить там основную разметку, а контент и шаблонизацию вынести для каждого блока в bemhtml/bemtree в common.blocks

И, вроде бы, всё почти сложилось, сами сущности расширяются, в итоговом html в браузере я вижу все блоки, которые должны были сформироваться. Но вот стили применились только к элементам, описанным в bemjson. А блоки, описанные через bemtree оказались проигнорированы в контексте css

Я вычистил из проекта лишнее и залил сюда - https://yadi.sk/d/NeU8Hc033MSDX2

Помогите плиз разобраться в чём дело, почему не применяются стили к topmenu__wrapper?

Добрый день Разрабатываю на project stub относительно большой проект (вёрстка):

  • несколько страниц
  • все страницы разные в контексте блоков, общие только шапка и подвал
  • на разных страницах свои особенные скрипты, которых нет на других страницах
  • разрабатывал страницы отдельно на отдельно взятых project stub заготовках
  • css блоков и bemhtml для каждой страницы клал в common.blocks

Теперь нужно всё это (все странички из разных project stub заготовок) собрать воедино, но пока не пойму как. Мне нужна примерно следующая картина в файловой структуре: common.blocks -- common ---- header ------ header.css ------ header.bemhtml.js ---- footer -- catalog ---- filter ---- heading -- index -- contacts desktop.bundles -- index -- catalog ---- catalog.html ---- catalog.bemjson.js ---- catalog.min.css ---- ... -- contacts

Как это реализовать? Где указать условия каким блокам со стилями из каких каталогов в какую страничку подгружаться? Потому что если я сейчас из разных заготовок стили солью в одну папку, у меня к каждой странице будут подгружаться все стили. Т.е. в contacts будет попадать что предназначалось для catalog и т.д.

Собрали проект на project-stub, с использованием bemjson и bemhtml . Теперь пытаюсь все это прицепить это к php через bh.php . Есть ли возможность на лету портировать bemhtml шаблоны в php, чтоб в дальнейшем использовать их у себя на сайте?

Добрый день

Разрабатываю адаптивный сайт на флексбоксах на основе project stub

Подскажите, как лучше организовать css с медиа-запросами в структуре project stub?

Допустим у меня такая структура: http://joxi.ru/eAOY9ZWsxZYgvm

Медиа-условия писать в этом же файле или создать отдельно какой-то другой?

Здравствуйте. Пытаюсь собрать блок на основе ответа от сервера через модуль http. У блока в *.bemhtml.js выполняю запрос и заполняю блок на основе ответа в callback-функции. Но сборщик не дожидается ответа и строит html дальше. Естественно блок выходит пустой. Как быть в этом случае?

var http = require('http');

var options = {
    host: 'localhost',
    path: '/TESTindex.php'
};

callback = function(response) {
    var str = '';

    //another chunk of data has been recieved, so append it to `str`
    response.on('data', function (chunk) {
        str += chunk;
    });

    //the whole response has been recieved, so we just print it out here
    response.on('end', function () {
        var items = JSON.parse(str);
        var response = [];
        for (var i = 0;i < items.length;i++) {
            item = items[i];
            response[i] = {
                title: item
            };
        }
        console.log('resp', response);
        createBlock(response);

    });
};

var createBlock = function (items) {
    console.log('1',items);
    block('testmenu').elem('content')(
        content()(function() {
            console.log('1,5');
            this.ctx.items = items;
            console.log('2',this.ctx.items);
            return this.ctx.items.map(function(item) {
             console.log('3',item);
                return {
                    elem: 'item',
                    content: [
                        {
                            elem: 'title',
                            content: item.title
                        }
                    ]
                };
             });
        })
    );
};

createBlock([
    {
        title: 'Один'
    },
    {
        title: 'Два'
    },
    {
        title: 'Три'
    }

]); // Если выполнить этот вариант, то блок строится правильно

http.request(options, callback).end(); // Если выполнить этот вариант, то в консоль выводится только '1', [....] и на этом останавливается, и блок выходит пустой.

Использую project-stub. Есть страница index(desktop.bundles). В ней подключаются блоки через конструкцию include:

var fs = require('fs'),
    path = require('path'),
    nodeEval = require('node-eval');

function include(filename) {
    return nodeEval(fs.readFileSync(filename, 'utf8'), filename);
}

module.exports = {
    block: 'page',
    head: [
        { elem: 'css', url: 'index.min.css' }
    ],
    scripts: [
        { elem: 'js', url: 'index.min.js' }
    ],
    content: [
        include('desktop.blocks/header/header.bemjson.js'),
    ]
};

Тем самым - это позволяет уйти от стандартного require, который кэширует содержимое. Но это не решает задачу в целом. Так как: Если изменить содержимое блока header и обновить страницу - изменения не подтянутся. Приходится вручную каждый раз делать любые изменения в самом index.bemjson.js (например добавив 1 таб), тогда блок header обновиться. Мое предположение: Сборщик считает, что файл index.bemjson.js не изменили и поэтому не пересобирает файл, а в блоках include ведь есть изменения. Возможно ли ему как то сообщить об этом, или отключить кэширование?

Доброго времени суток!

Наткнулся на очень странное поведение блока select с модификатором radio-check. Берем bemjson из документации:

{
    block : 'select',
    mods : { mode : 'radio-check', theme : 'islands', size : 'm' },
    name : 'select3',
    val : 2,
    text : '—',
    options : [
        { val : 1, text : 'Доклад' },
        { val : 2, text : 'Мастер-класс' },
        { val : 3, text : 'Круглый стол' }
    ]
}

несколько раз клацаем, меняем выбранное значение - все прекрасно. Но так как далеко не всегда существует значение по-умолчанию, убираем val:

{
    block : 'select',
    mods : { mode : 'radio-check', theme : 'islands', size : 'm' },
    name : 'select3',
    text : '—',
    options : [
        { val : 1, text : 'Доклад' },
        { val : 2, text : 'Мастер-класс' },
        { val : 3, text : 'Круглый стол' }
    ]
}

и повторяем манипуляции. Вот тут и начинаются странности: проклацав по-очереди все пункты получаю примерно такую разметку:

...
<div class="select select_mode_radio-check select_theme_islands select_size_m i-bem select_js_inited" data-bem="{&quot;select&quot;:{&quot;name&quot;:&quot;select3&quot;,&quot;text&quot;:&quot;—&quot;}}">
  <input type="hidden" name="select3" class="select__control" value="3">
  <input type="hidden" name="select3" class="select__control" value="2">
  <input type="hidden" name="select3" class="select__control" value="1">
  <button class="button button_size_m button_theme_islands select__button button__control i-bem button_js_inited button__control_js_inited _popup-destructor_js_inited button_checked" data-bem="{&quot;button&quot;:{}}" role="listbox" aria-owns="uniq14993408571141 uniq14993408571142 uniq14993408571143" aria-labelledby="uniq14993408571144" type="button">
    <span class="button__text i-bem button__text_js_inited" id="uniq14993408571144">Круглый стол</span>
    <span class="icon select__tick"></span>
  </button>
</div>
...

Версия bem-components 6.0.0

Здравствуйте. Есть блок с названием 'secondary-menu-bottom'. У него есть блок 'menu' с массивом 'items' и контент из одного item. Задача: Необходимо в шаблоне "смапить" массив items, до первого item-a, который уже существует в content. ApplyNext() почему то отказывается работать в связке c map. Если убрать map и оставить ApplyNext() - ошибок не будет. И аналогично с комментированием ApplyNext() - map сделает своё дело Ошибка: TypeError: Cannot read property 'map' of undefined

/ secondary-menu-bottom.bemjson.js /

module.exports = {
    block: 'secondary-menu-bottom',
    content: {
        block: 'menu',
        content: [
            {
                elem: 'item',
                content: include('desktop.blocks/more/more.bemjson.js')
            }
        ],
        items: [
            {
                url: '/',
                title: 'Все рецепты'
            },
            {
                url: '/',
                title: 'Салаты и закуски'
            }
        ]
    }
};

/ secondary-menu-bottom.bemhtml.js /

block('secondary-menu-bottom').extend()({ _inSecondaryMenuBottom: true });

block('menu').match(function() { return this._inSecondaryMenuBottom; })(
    content()(function() {
        return [
            this.ctx.items.map(function(item) {
                return {
                    elem: 'item',
                    content: { block: 'link', url: item.url, content: item.title }
                };
            }),
            applyNext()
        ]
    })
);

Добрый день! Вопрос про инициализацию слайдера. Написал простенький слайдер, который работает, но таких слайдеров нужно 2, а может и больше на одной страничке.

Как их разграничить правильнее, сейчас все действия выполняются на последнем слайдере если их размещено 2 и более. gallery.bemjson.js

{
  block:'show-gallery',
  js:{step:4},
  content:[
            {
              elem:'holder',
            },                                                                                                                                                                                                                                                      
            {
             elem:'dop-foto',
             content:[
                      {
                       elem:'control-next',
                       content:''
                      },
                      {
                       elem:'control-prev',
                       content:''
                      },                                                                                                                                
                      {
                       elem:'list-outer',
                       content:[
                                {
                                  elem:'list',
                                  tag:'ul',                                                                                                                                                                          
                                  content:[
                                            {                                                                                                                                          
                                              elem:'item',
                                              block:'show-gallery',
                                              js:{slideid:1, slide:1,  src:'images/show_max_2.jpg'},
                                              tag:'li',
                                              content:[
                                                       {
                                                         block:'image',
                                                         tag:'img',
                                                         url: 'images/show_mini_2.jpg',
                                                       }
                                                      ]
                                            },
                                            {                                                                                                                                          
                                              elem:'item',
                                              block:'show-gallery',
                                              js:{slideid:1, slide:2,  src:'images/show_max_1.jpg'},
                                              tag:'li',
                                              content:[
                                                       {
                                                         block:'image',
                                                         tag:'img',
                                                         url: 'images/show_mini_1.jpg',
                                                       }
                                                      ]
                                            },
                                            {                                                                                                                                          
                                              elem:'item',
                                              block:'show-gallery',
                                              js:{slideid:1, slide:3,  src:'images/show_max_3.jpg'},
                                              tag:'li',
                                              content:[
                                                       {
                                                         block:'image',
                                                         tag:'img',
                                                         url: 'images/show_mini_3.jpg',
                                                       }
                                                      ]
                                            },
                                            {                                                                                                                                          
                                              elem:'item',
                                              block:'show-gallery',
                                              js:{slideid:1, slide:1,  src:'images/show_max_4.jpg'},
                                              tag:'li',
                                              content:[
                                                       {
                                                         block:'image',
                                                         tag:'img',
                                                         url: 'images/show_mini_4.jpg',
                                                       }
                                                      ]
                                            },
                                            {                                                                                                                                          
                                              elem:'item',
                                              block:'show-gallery',
                                              js:{slideid:1, slide:1,  src:'images/show_max_5.jpg'},
                                              tag:'li',
                                              content:[
                                                       {
                                                         block:'image',
                                                         tag:'img',
                                                         url: 'images/show_mini_5.jpg',
                                                       }
                                                      ]
                                            },
                                   ]
                            }                                                                                                                                
                         ]
                      }
                   ]
},

show-gallery.js

modules.define('show-gallery', ['i-bem-dom','jquery',  'BEMHTML' ], function(provide, bemDom,$, BEMHTML) {

provide(bemDom.declBlock(this.name, {
    onSetMod: {
        'js': {
            'inited': function() {
            console.log('Слайдер инициализирован')
            var domElem = this.domElem;
                 counter = 0;
                 holderMain = this._elem('holder');
                 innerBl = this._elem('list-outer');
                 slides = this._elem('list');
                 slide = this._elem('item');
                 step = this.params.step;
                 position = 0;
                 console.log('Шаг слайдера', step);
            //Ширина блока под фотографию главную
                 this.holderMainWidth = holderMain.domElem.width(); 
                 console.log('Ширина блока под фотографию главную', this.sliderMainWidth);
            //Высота блока под главную фотографию
                 this.holderMainHeight = this.holderMainWidth / 1.54;
                 console.log('Высота блока под фотографию главную', this.sliderMainHeight);
                 holderMain.domElem.css({ height: this.holderMainHeight});
            //Ширина каждого слайда
                 this.slideWidth = slide.domElem.width(); 
                 console.log('Ширина слайда', this.slideWidth);
            //Видимая ширина слайдбара
                 slidesWidth = this.slideWidth * step;
                 console.log('Видимая ширина слайдбара', innerWidth);
                 innerBl.domElem.css({ width: slidesWidth}); 
            //Определяем ширину всех элементов
            var _this = this;
                 this._elems('item').forEach(function(elem) {
                          counter++;    
                      });
                 console.log('Число элементов', counter);
                 slidesWidthFull = this.slideWidth * counter;
                 console.log('Общая ширина слайдбара', slidesWidthFull);
                 slides.domElem.css({transform: 'translate3d(0px, 0px, 0px)', transition: '0s', width: slidesWidthFull}); 


            //Сдвигаем слайды влево
                 this._domEvents('control-prev').on('click', function(e) {
                 console.log('клик по gравому контролу');
                 position = Math.min(position + this.slideWidth * step, 0);
                 test = 'translate3d('+position+'px, 0px, 0px)';
                 console.log('Определяем на сколько сдвинуть', position);
                 slides.domElem.css({transform: test, transition: '250ms', width: slidesWidthFull});
                 }); 
            //Сдвигаем слайды вправо 
                 this._domEvents('control-next').on('click', function(e) {
                 console.log('клик по левому контролу');
                 val1 = position - this.slideWidth * step;
                 val2 = -this.slideWidth * (counter - step) 
                 position = Math.max(val1, val2);
                 test = 'translate3d('+position+'px, 0px, 0px)';
                 console.log(test);
                 slides.domElem.css({transform: test, transition: '250ms', width: slidesWidthFull});
                 }); 
            //Кликаем по слайду
                 this._domEvents('item').on('click',this._onCurSlide);
            //Определяем первый активный элемент
                 this._events('item').on({ modName : 'active', modVal : true },this._onCurSlides);
                 this._elem('item').setMod('active');





            }
        },
        },
        _onCurSlide: function(e) {
            var curSlide = e.bemTarget.params.slide;
                curSrc = e.bemTarget.params.src;
                oneId = e.bemTarget.params.id;
                console.log(curSlide);
                console.log(curSrc);
            var sliderMain =  {
                                    block: 'show-gallery-image',
                                    js:{src:curSrc},
                                    content: [
                                                {
                                                    elem:'image',
                                                    tag:'img',
                                                    attrs:{src:curSrc}
                                                },
                                                // {
                                                //     elem:'zoom',
                                                // },
                                    ]   
                                };
            html = BEMHTML.apply(sliderMain);
            console.log('формируем html', html);
            bemDom.update(holderMain.domElem, html);
    },
    _onCurSlides: function(e) {
          var oneSlide = e.bemTarget.params.slide;
              oneSrc = e.bemTarget.params.src;
              oneId = e.bemTarget.params.id;

            console.log('Номер первого слайдера', oneSlide ,oneSrc );
            var sliderMainDefault =  {
                                    block: 'show-gallery-image',
                                    js:{src:oneSrc},
                                    content: [
                                                {
                                                    elem:'image',
                                                    tag:'img',
                                                    attrs:{src:oneSrc}
                                                },
                                                // {
                                                //     elem:'zoom',
                                                // },
                                    ]   
                                };
            html = BEMHTML.apply(sliderMainDefault);
            console.log('формируем шаблон html по умолчанию', html);
            bemDom.update(holderMain.domElem, html);
    },




}));

});

Добрый день.

В примере по созданию проекта на БЭМ (https://ru.bem.info/platform/tutorials/start-with-project-stub/), на шаге добавления картинки в блок logo, фрагмент определения блока image из примера на сайте выглядит так:

            block: 'image',
            attrs: { src: 'some-url' }

При этом в результате сборки в html попадает только: <img class="image">

По аналогии с другими блоками попробовал переписать определение так:

            block: 'image',
            url: 'some-url'

И получилось ожидаемое: <img class="image" src="some-url">

Подскажите, в чём здесь дело?

Не нашёл способ передать собственный идентификатор в компонент popup группы dropdown из bem-components.

Имеется в виду установка того идентификатора, который используется для связи popup и dropdown_switcher_button.

Как ни пытаюсь, в коде всё равно присутствует ... id="uniq14912161426251"

Максимум, чего удаётся добиться, это <popup ... data-bem='{"popup":{},"dropdown":{"id":"appUserNameDropdown"}}'>, но id всё равно uniq....

Как???

UPD

Так понял, это xjst'шный generateId(), безусловно дёргаемый в dropdown для получения своёства id, который в свою очередь дёргает this.identify(this.ctx), который вроде должен подхватывать свойство this.ctx.uniqueID (как я пробовал сначала), но на самом деле нет. (Такое ощущение, что до того identify, что находится в составе bem-core, дело даже не доходит, если это возможно...)

UPD

Ну да, конечно, там (bem-xjst/lib/bemhtml/bundle.js) свой indentify, вот такой:

exports.identify = function identify(obj, onlyGet) {
  if (!obj)
    return getUniq();
  if (onlyGet || obj[uniqExpando])
    return obj[uniqExpando];

  var u = getUniq();
  obj[uniqExpando] = u;
  return u;
};

который вообще никуда не смотрит.

Т.е., выходит, расширять dropdown (popup?), чтобы переопределять нужные методы/свойства? Как правильно?

Добрый день. Ребята, я начинающий разработчик, просьба сильно не ругать (документацию честно читаю, стараюсь разобраться). Столкнулся с определенной проблемой, подскажите направление, чтобы разобрался дальше самостоятельно. Суть вопроса, чисто теоретически: В проекте на первой страничке хочу сделать универсальную шапку (header), содержащую контейнер (container) , который содержит 3 блока (logo, nav и text-area). Контейнер буду использовать для позиционирования блоков. По задумке, вариантов контекста блока (text-area) будет несколько и на разных страничках буду их подключать по текущему смыслу к контейнеру, путем микширования, если я правильно понимаю. Но, я где-то должен описать все варианты структур данного блока, пока не имею ввиду его оформление, сам контекст.

Вопрос: не могу понять, в index.bemjson.js описать блок могу, текущую разметку 1 варианта получу, но где описать остальные варианты структуры этого блока?

Добрый день! Начинаю изучать БЭМ (методологию и инструменты). В процессе практики возник следующий вопрос. Как на последний элемент в наборе навесить класс. Есть меню с пунктами. Для последнего пункта нужен класс для особого оформления. Как это сделать в шаблонизаторе разобраться не могу. Подскажите, пожалуйста!

https://jsfiddle.net/8a6j3njg/

Добрый! Есть таск

function less() {
  return bundler('*.bundles/*')
    .pipe(builder({
      less: bundle => {
        bundle.src('less')
          .pipe(gulpLess())
          .pipe(postcss([
            postcssImport(),
            postcssUrl({ url: 'inline' }),
            autoprefixer({browsers: prefixes}),
            postcssReporter()
          ]))
          .pipe(concat(bundle.name + '.min.css'))
          .pipe(gulpif(isProd, csso()))
      }
    }))
    .on('error', console.error)
    .pipe(debug())
    .pipe(gulp.dest(file => path.dirname(file.path)));
}

Крашится

TypeError: Cannot read property 'block' of undefined
    at data.forEach.dep (/home/arsen/dev/nodeprojects/njs_nian/node_modules/@bem/deps/lib/formats/deps.js/parser.js:29:37)
    at Array.forEach (native)
    at depsData.forEach.record (/home/arsen/dev/nodeprojects/njs_nian/node_modules/@bem/deps/lib/formats/deps.js/parser.js:27:14)
    at Array.forEach (native)
    at parse (/home/arsen/dev/nodeprojects/njs_nian/node_modules/@bem/deps/lib/formats/deps.js/parser.js:23:14)
    at Promise (/home/arsen/dev/nodeprojects/njs_nian/node_modules/@bem/deps/lib/parse.js:11:25)
    at /home/arsen/dev/nodeprojects/njs_nian/node_modules/@bem/deps/lib/parse.js:9:16

Есть каталог common.blocks в корне, там button, внутри .js файл, .browser.js, .less, .deps.js и Page, в нем те же технологии

Билдер

const builder = Builder({
  levels: [
    'common.blocks',
    'desktop.blocks'
  ],
  techMap: {
    bemhtml: ['bemhtml.js'],
    js: ['js'],
    less: ['less']
  }
});

Что я делаю не так? Хотелось бы поподробнее узнать о библиотеках

const Builder = require('gulp-bem-bundle-builder');
const bundler = require('gulp-bem-bundler-fs');

И можно ли с помощью них полноценно собирать БЭМ проекты на gulp?

Всем привет. К примеру есть такой вот bemjson

{
    block: 'b1',
    content: [
        {
            block: 'b2',
            mix: {block: 'b1', elem: 'e1'},
            content: [
                {
                    elem: 'e1',
                    content: 'title'
                },
                {
                    elem: 'e2',
                    content: 'description'
                }
            ]
        },
        {
            block: 'b2',
            mix: {block: 'b1', elem: 'e1'},
            content: [
                {
                    elem: 'e1',
                    content: 'title'
                },
                {
                    elem: 'e2',
                    content: 'description'
                }
            ]
        }
    ]
}
Допустим блок b1 это какой-то список, b2 это элемент списка который может использоваться еще где-то на странице но не в виде элемента списка а просто в виде блока. Но вот дилемма, если примиксовать к b2 элемент блока b1e1 и задать ему bemhtml в котором бы говорилось что b1e1 должен иметь тег li то этот код не срабатывает. Напрямую в bemjson писать не хочется tag. Пробовал прописывать всякого рода зависимости, блока b2 от блока b1, блока b2 от элемента e1 блока b1 и блока b1 от элемента e1. Как будет правильно поступать в данной ситуации?

Уважаемые бэмчане,

не сочтите за оффтоп, но хотелось бы услышать ваше мнение. Angular2 и Vue, например, имитируют scoped css через присваивание уникального атрибута всем тегам и добавление его же к селекторам в css. Возникла идея сделать эти трансформации приближенными к бэм методологии. Представьте, что у нашей компоненты шаблон и стили такие:

<section class='product'>
    <header class='title'>
        Foo 
        <span class='hint'></span>
    </header>    
</section>

.product { /* ... */ }
.product .title { /* ... */ }
.product .title .hint { /* ... */ }

Тогда пропустив шаблон и стили через наш преобразователь получим следующее:

<section class='product_ABC product'>
    <header class='product_ABC__title title'>
        Foo 
        <span class='product_ABC__title_hint hint'></span>
    </header>    
</section>
.product_ABC { /* ... */ }
.product_ABC__title { /* ... */ }
.product_ABC__title_hint { /* ... */ }

Принцип прост, по возможности заменить и сделать стили плоскими. Сохранить изначальный селектор Элементов и пройтись по шаблону Добавив новые имена классов. Изначально селекторы всегда вида: BLOCK(…modifiers) ELEMENT(…modifiers) … . Модификаторы мы не изменяем. В следующем примере селектор плоским сделать мы не можем, так как он зависит от состояния родителя:

.product.active .title {}

.product_ABC.active .product_ABC__title { }

Плюсы данного подхода:

  • Разработка блока/компоненты не зависит от инструментария, как Css Modules, например
  • Все стили после сборки под селекторами с уникальной солью - нет коллизий
  • Все селекторы максимально плоские - хорошо для производительности
  • Минимальная специфичность селекторов - хорошо для переопределения
  • Все изначальные классы в html остаются не тронуты - если вдруг нам нужно искать элементы из js, добавлять модификаторы, или определять новые стили по этим селекторам.

Недостатки:

  • Работает в компонентной архитектуре, где шаблон инкапсулирован в отдельный блок.

Дополнительно:

  • Можно от соли отказаться, и гарантировать уникальность блоков самому, тогда селекторы всегда будут детерминированны.
  • Можно ввести некоторые соглашения об именах на случай каких либо "edge case".
  • Можно от имени блока отказаться и генерировать его другим способом, а в стилях использовать ":host" для его стилизации.

Простите, что возможно сумбурно выразился, старался как можно компактнее подать идею. Есть ли у кого-то мысли по этому поводу?

Всем привет!! Понимания схемы работы динамического сайта - нет. Есть понимание работы динамических страниц сайта в схеме:

  • MySQL(db) -> PHP ->HTML. В такой схеме робот индексирует страницу как HTML. Предполагаю что схема выглядит так:
  • MySQL(db) -> BEMTREE -> BEMJSON -> HTML А как происходит при схеме по БЭМ-шаблонам? Как индексируются сайты с движком JS, вместо PHP ???

Существует элемент 'icon' блока 'button' с модификатором 'close'

common.blocks/button/__icon/_close/button__icon_close.styl --- технология CSS

в index.bemjson.js блок выглядит таким образом:

{
    block : 'button',
    mix : { block : 'sitemap', elem : 'button' },
    attrs : { title : 'Закрыть меню' },
    icon : {
        elem : 'icon',
        elemMods : { close : true }
    }
}

Стили модификатора не собираются. Как и стили элемента button__icon. Замена 'icon' на 'content' - не помогает.

Особенность данной проблемы: на одном компе всё собирается, на домашнем - нет. На домашнем вчера обновлял модули связанные с БЭМ-методологией. Что именно обновлял - не помню. Переустановка с полной чисткой проекта - не помогла.

Народ, если ошибки нет - помогите разобраться в чем проблема. Может уже кто-нибудь сталкивался?

Подскажите как сделать так, чтобы по файлу BEMJSON папки и файлы(стилей скриптов и др) создавались сами.

Вроде бы с помощью БЭМ тулс говорили можно, прочитал, но как это сделать ответа не нашел.

P.S. Чтобы подключить bem-tools нужно на уровне проекта прописать npm install bem верно ? или просто в терминале это прописать? Куда он тогда установится

P.P.S. В документации к тулзу написанно, что можно создавать для БЭМ сущностей css, js файлы, а так же bemhtml. Нужно ли это делать или bemhtml идет один на бандл(страницу).

Прочитал документацию и возник вопрос как создать свой первый сайт по БЭМ

А конкретно работа с BEMJSON файлом и сборщиком.

Как новичку сложно разобрать пример на сайта методологии. Может кто сможет объяснить простыми словами. На примере "Hell World" Без использования полного комплекта project-stub

Думаю многим новичкам будет интересно. Как по пунктам создать сайт с фразой Hell World Используя BEMJSON и сборщик!

Имеется стандартный JSON кнопки -> block : 'button', mods : { theme : 'islands', size : 'm', view : 'action'}, text : 'Создать' В html мы получаем: <button class="button button_theme_islands button_size_m button_view_action button__control i-bem button_js_inited" data-bem="{&quot;button&quot;:{}}" role="button" type="button"><span class="button__text">Создать</span></button>. К данному html мне нужно ещё добавить элемент к JSON чтобы в конечном результате в html вышло: <button class="button button_theme_islands button_size_m button_view_action button__control button__add-form i-bem button_js_inited" data-bem="{&quot;button&quot;:{}}" role="button" type="button"><span class="button__text">Создать</span></button>.

у нас есть несколько разделов сайта. Админка, профиль, публичная часть. Сейчас собирается 3 merged бандла. При этом на публичной части много разных страниц. Хотелось бы иметь что то вроде core.js, core.css куда попадут стили и скрипты общие для всех страниц публичной части, и маленькие js и css для каждой отдельной страницы, где будут уникальные стили-скрипты для нее. Как это сделать?

В проекте есть часть системы (модель) с использованием организации файлов по БЭМ и YModules, которая не зависит от вью и могла бы загружаться асинхронно.

Вопрос, куда прописать зависимость бандла от блоков без DOM-представления модели?

Если прописать модель в BEMJSON виде пустого блока, то у блока page появляется зависимость от модели и асинхронной инициализации визуальных блоков внутри page не происходит.

Здача: матчить элемент блока с модификатором. Вроде бы должно быть так ведь: block('b').mod('m', true).elem('e')( ... );? Сам по себе блок+мод отлавливается замечательно: block('b').mod('m', true). Аналогично -- вложенный элемент block('b').elem('e')( ... );. Но всё вместе никак почему-то не удаётся. Что я делаю не так?

Хочу в шаблоне выбрать (по имени) вложенные в блок элементы и... ч.-ндь к ним применить.

Вижу, что в match у меня this.elem всегда undefined, а elemMatch (про который где-то что-то попадалось) почему-то отсутствует.

Как правильно поступить?

Всем привет! Создали худо бедно страничку сайта со структурой лендинга, и там хотелось использовать анимацию на основе svg. Пока отдельно существует анимация, svg+js, отдельно страница без интеграции в Битрикс сделанная на bem+gulp. Вопрос6 есть ли примеры совмещения уже в bemjson анимации svg

Добрый день! Начал верстку интернет-магазина в котором более 30 страниц. И тут же заказчику уже захотелось кое-что поменять в шапке. Страшно представить, что когда будет сверстан весь проект и начнутся правки, то придется ходить по ВСЕМ страницам и менять что-то в одинаковых блоках (header, footer, menu, rightbar и т.д.). Это будет просто самоубийство, и при всём уважении к данной методологии и её способности увеличивать скорость создания проектов, для данного случая эту будет намного дольше. Я пересмотрел и перечитал уже кучу материалов, но, блин, не могу сделать, чтобы это было корректно и удобно. Подскажите кто-нибудь, пожалуйста, как такое реализовать. Ведь полюбому есть решения данной проблемы, т.к. БЭМ используется, в основном, в крупных проектах. Прям очень очень прошу помощи и указать как такое реализовать, потому что не хочется, особенно при верстке такого крупного проекта, отказываться от БЭМ. Да, использую в качестве сборщика gulp, т.е. как реализовать это всё на нём. Спасибо!