Возникла проблема с this
. Каждый с ней сталкивался, когда приходилось что-то делать с фильтрами или чем-то другим. Приходилось кэшировать в переменную self
Или, например, каждый раз при смене модификатора элемента приходилось писать что-то типо этого
this.setMod( this.elem('right'), 'size', 'xxxxl' );
много раз приходится дублировать this... А иногда не сразу понятно на что он ссылается. При создании одного из блоков я подобрал для себя решение, может кому пригодится.
modules.define('scroller', ['i-bem__dom', 'jquery'], function(provide, BEMDOM, $) {
var block;
function elem(name) {
return block.elem(name);
}
BEMDOM.decl(this.name, {
onSetMod: {
'js' : {
'inited' : function() {
block = this;
}
}
},
}, {});
provide(BEMDOM);
});
После чего к блоку всегда можно обращаться через block
а к элементу через elem('name')
.
например установка модификатора для элемента теперь будет выглядеть так:
block.setMod( elem('right'), 'size', 'xxxxl' );
из плюсов
- однозначность
block
- более короткая запись для доступа к элементам
elem('name')
- 4 строчки кода
П.Н. Данное решение актуально для bem-core@v2, в bem-core@v3 - решение будет лучше из коробки.
@tatudata ниже объяснил, почему так нельзя. В ответах есть другие предложения.
Что есть в ответах
Добавлена реализация короткой записи модификации элементов вида:
this.el('body')
.setMod('size', 'xxx')
.setMod('color', 'gray);
@belozyorcev Не-не-не-не-не, Девид Блейн! Нельзя так делать!
this
должен указывать на экземпляр каждого блока, а тут получается, что он всегда будет указывать на того, кто последний инициализировался.Чтобы было понятно о чем речь, добавь в своем примере подписку на клик и положи несколько
scroller
на страницу:JFYI, методы типа
filter()
,map()
илиforEach()
последним необязательным параметром принимают контекст, как и многие из методовi-bem.js
.@tadutata
а разве функция не задаёт "замыкание" переменной?
function(provide, BEMDOM, $) {}
В том-то и дело ;)
Тут важно понимать, что модуль в памяти создается один раз, а onSetMod js inited дергается столько раз, сколько блоков окажется на странице. И в замыкании останется ссылка на тот экземпляр блока, который заинитится последним.
Эххх ) Жаль... Решение было так близко )
@tadutata Есть ещё один вариант, вдохновлённый bem-core@v3
Что скажешь?
Такую вещь проще доопределить в блоке i-bem__dom на уровне проекта, чтоб не копипастить в каждый блок
@Guria, как раз начал задумываться над этим :) А за намёк спасибо )
Ребята, что вы делаете? Если уж сильно хочется писать
this.elem().setMod
- расширьте jQuery.fn один раз и пишите.Я пока пользуюсь тем что дают и не парюсь :)
Короткая запись модификации элементов
было:
стало:
Реализация
П.Н. спасибо @Guria за подсказку
@apsavin А как узнать при этом к какому блоку элемент относится?
@belozyorcev вроде норм, только тогда надо другими методами приправить
@Guria @belozyorcev Мне нравится идея дорулить
.setMod
и другие функции в$.fn
, но я не очень понимаю, как это можно сделать без знаний о блоках, к которым этот элемент относится.Но если делать через
this.el
— может быть проще один раз в$.fn
дописать.setMod
и другие функции, а в.el
засовывать сам блок в возвращаемый jQuery-chain? Ну и при использовании без блока просто ругаться.upd Кажется, при использовании
$('.some-class__some-elem')
(равно как иthis.elem('some-elem')
) мы будем иметь в jQuery-chain свойствоselector
(еяпп) с нужными нам данными, которые надо будет просто распарсить.Кажись понял. Не нравится то, что в предложенном решении к каждому элементу навешивается свой отдельный метод? Причём при каждом вызове
.el
. Действительно, наверное не очень хорошо.@Guria В том числе, но еще и
this.el
можно было бы заменить наthis.elem
.@tadatuta А как рулятся такие ситуации?
Элемент внутренний будет в обоих блоках виден?
@zxqfox - боюсь что через $.fn решение окажется более громоздким. Вдобавок ко всему нужно следить за кэшем БЭМ.
@belozyorcev Но и более универсальным ;-) И не будет путаницы между
.el
и.elem
@zxqfox - желание было сделать через
.elem
, дабы реализовать "подготовительный" этап перед bem-core@v3 Но пока это.el
.Может как-то так?
@zxqfox я думаю, что в таком случае тебе может помочь
this.findElem('elem', true);
. СоstrictMode
i-bem
не будет искать элемент глубже.В bem-core@v2 есть экспериментальная фича, реализующая работу с инстансами элементов. Для ее использования достаточно добавить в зависимости блока следующее:
Тогда можно устанавливать модификатор напрямую у инстанса элемента:
Кроме того, можно работать с БЭМ-событиями на элементах, создавать для них декларации и т.д.
@aristov ооо :) Правда запись немного длинная получается
@belozyorcev да, но для нас читаемость и понятность кода важнее краткости его написания.