{"id":28857114,"url":"https://github.com/rubaxa/jquery.bem","last_synced_at":"2025-07-04T01:33:45.220Z","repository":{"id":3488326,"uuid":"4544234","full_name":"RubaXa/jquery.bem","owner":"RubaXa","description":"jQuery BEM (Development of the project is closed)","archived":false,"fork":false,"pushed_at":"2024-05-30T10:46:18.000Z","size":174,"stargazers_count":20,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-20T01:14:00.552Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://rubaxa.github.io/jquery.bem/example.html","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RubaXa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2012-06-04T06:56:46.000Z","updated_at":"2024-05-30T10:46:06.000Z","dependencies_parsed_at":"2025-06-20T01:13:27.032Z","dependency_job_id":"77f31aee-2de9-416c-a2d0-56a4900319b4","html_url":"https://github.com/RubaXa/jquery.bem","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/RubaXa/jquery.bem","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubaXa%2Fjquery.bem","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubaXa%2Fjquery.bem/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubaXa%2Fjquery.bem/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubaXa%2Fjquery.bem/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RubaXa","download_url":"https://codeload.github.com/RubaXa/jquery.bem/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubaXa%2Fjquery.bem/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263430551,"owners_count":23465398,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-20T01:13:05.028Z","updated_at":"2025-07-04T01:33:45.207Z","avatar_url":"https://github.com/RubaXa.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# jQuery BEM\n\nЭто инструмент, предназначенный для описания поведения DOM элемента в BEM терминологии.\n[demo](http://rubaxa.github.com/jquery.bem/example.html)\n\n\n## Зачем это нужно?\n\nКаждый из нас, хоть раз, сталкиваться с задачей, в рамках которой\nнужно стилизовать элемент формы или сделать какой-то свой контрол. И тут\nприходится сделать выбор, отправиться в гугл или написать самому. Знакомая\nистория, не правда ли?\n\nМне попадались разные библиотеки, но у них было одно общее - их нужно\nиницализировать. Есть конечно такие, которые делают инициализацию по DOMReady. Но\nчто делать с теми элементами, которые мы создали позже, например,\nполучив контен через ajax?\n\nКроме того, инициализация по DOMReady замедляет загрузку страницы. В тоже время,\nвелика вероятность, что пользователь не использует стилизованный элемент,\nа он может быть не один. Тогда зачем нужно тратить рессурсы на их инициализацию?\n\nВсе эти проблемы меня очень печалили, а ведь хотелось простого -  чтобы\nвсе работало само и по необходимости, как бы смешно это не звучало :]\n\nИдея сформировалась давно и не нова. Суть её проста - в верстке мы используем\nCSS для определения стиля элемента, описываем селектор и дальше применяем его\nк нужным элементам. Еще есть BEM c блок, элемент и модификатор, осталось\nтолько описать поведение для этого нужного блока, и дело в шляпе\n\n\nДля себя я сформировал следующие требования:\n * Все необходимые элементы находятся в верстке изначально. Ничего не генирируется скриптом во время исполнения страницы.\n * Инициализация происходит по необходимости, т.е. перед непосредственным  использованием\n * Поведение максимально приближено к нативному\n * Код прозрачен как для верстальшика, так и разработчика\n * Расширямость (возможность написания своих компонентов)\n\n\nВ итоге, я получил иструмент, который позволил мне описывать поведение\nэлемента для нужного селектора. Если применить класс `b-button`к некоторому элементу,\nто этот элемент будет вести себя, как кнопка, со всеми состояниями\nи событиями присущими кнопке. И самое замечательное, что не нужно беспокоиться о его инициализиции.\n\n\n\n## Пример 1\nРассмотрим простой пример, вам нужно, чтобы при наведении на элемент, к нему добавлялся\nмодификатор `_hover`, а при фокусе (например при помощи tab) `_focus`:\n```html\n\u003ca href=\"#\" class=\"link\" tabindex=\"1\"\u003elink\u003c/a\u003e\nили\n\u003cspan class=\"link\" tabindex=\"2\"\u003e...\u003c/span\u003e\n```\n```js\n$.bem('link', null, {\n\t// static methods and properties\n\tmods: 'focus hover'\n});\n```\n\n\nИ все, больше никаких телодвижений, теперь если вы наведетесь на элемент с классом \"link\",\nто получите:\n```html\n\u003ca href=\"#\" class=\"link link_hover\" tabindex=\"1\"\u003elink\u003c/a\u003e\n```\n\n\n## Пример 2\nПример посложней, нам нужно сделать счетчик подсчета введенных символов:\n```html\n\u003cdiv class=\"b-input\"\u003e\n\t\u003cinput value=\"\" type=\"text\" class=\"b-input__input\" /\u003e\n\t\u003cspan class=\"b-input__length\"\u003e\u003c/span\u003e\n\u003c/div\u003e\n```\n```js\n$.bem('b-input', {\n\t_onKeyUpCalc: function (){\n\t\t// Работа с элементами, внутри блока\n\t\tthis.$('__length').text( this.$('__input').val().length );\n\n\t\t// можно и так\n\t\t// this.$('.b-input__length').text( this.$(':input').val().length );\n\t}\n}, {\n\tcache: true, // кешировать выборки\n\tlive: {\n\t\t'focusin focusout': function (evt){\n\t\t\t// обработчик события \"keyup\" назначаем в зависимости от фокуса\n\t\t\tthis[evt.type == 'focusin' ? 'on' : 'off']('keyup.calc', '_onKeyUpCalc');\n\t\t}\n\t}\n});\n```\n\n\n## b-button\nВот и настало время написать полноценный элемент-контрол-кнопка\n```html\n\u003ca href=\"...\" class=\"b-button\" tabindex=\"1\"\u003e\n\t\u003cspan class=\"b-button__label\"\u003ebutton\u003c/span\u003e\n\t\u003cinput type=\"submit\" class=\"b-button__input\" /\u003e\n\u003c/a\u003e\n```\n```js\n$.bem('b-button', {\n\trole: 'button',\n\n\tonMod: {\n\t\tdisabled: function (state){\n\t\t\tvar attrs = { disabled: state };\n\n\t\t\t// Сохраним url ссылки\n\t\t\tthis._href = state || !this._href ? this.$attr('href') : this._href;\n\n\t\t\tthis\n\t\t\t\t.$aria(attrs)\n\t\t\t\t.$attr(attrs)\n\t\t\t\t.$attr('href', state ? null : this._href) // установить или удалить href, в зависимости от состояния\n\t\t\t;\n\n\t\t\tif( state ){\n\t\t\t\t// кнопка disabled, так что удалим все модификаторы\n\t\t\t\tthis.delMod('hover focus press');\n\t\t\t}\n\t\t},\n\n\t\tpress: function (state){\n\t\t\tthis.trigger(state ? 'press' : 'release');\n\t\t},\n\n\t\thover_no: function (){\n\t\t\tthis.delMod('press');\n\t\t},\n\n\t\tfocus: function (state){\n\t\t\tif( state ){\n\t\t\t\t// вешаем событие за пределами элемента\n\t\t\t\tthis.onOutside('keydown.focus', 'onFocusKeyDown');\n\t\t\t} else {\n\t\t\t\tthis.offOutside('keyup.focus keydown.focus');\n\t\t\t}\n\t\t},\n\n\t\t'*': function (mod, state){\n\t\t\tif( state \u0026\u0026 this.isDisabled() ){\n\t\t\t\treturn\t!~'press hover focus'.indexOf(mod);\n\t\t\t}\n\t\t}\n\t},\n\n\n\tonClick: function (evt){\n\t\tif( !this.isDisabled ){\n\t\t\tthis.$('__input').click();\n\t\t}\n\t},\n\n\n\tonFocusKeyDown: function (evt){\n\t\tif( !this.hasOn('keyup.focus') ){\n\t\t\tthis.on('keyup.focus', function (evt){\n\t\t\t\tif( this.hasMod('press') ){\n\t\t\t\t\tthis.onClick(evt);\n\t\t\t\t}\n\t\t\t\tthis.delMod('press').off('keyup.focus');\n\t\t\t});\n\t\t}\n\n\t\tvar key = evt.keyCode;\n\t\tif( key == 13 || key == 32 ){\n\t\t\tthis.addMod('press');\n\t\t\tevt.preventDefault();\n\t\t}\n\t}\n}, {\n\tmods: 'hover press focus',\n\tlive: {\n\t\tleftclick: 'onClick'\n\t}\n});\n```\n\n\n### Наследование:\n```js\n$.bem(['b-button', 'b-submit'], {\n\tonMod: {\n\t\t'*': function (mod, state){\n\t\t\tvar ret = this.parent(mod, state);\n\t\t\t// you logic ...\n\t\t}\n\t},\n\n\tonFocusKeyDown: function (evt){\n\t\t// you logic ...\n\t\tthis.parent(evt); // call parent method\n\t}\n});\n```\n\n\n------------------------------------------\n\n\n\n## Готовые элементы\n\n### b-control\n * b-control_hover\n * b-control_focus\n * b-control_press\n * b-control_disabled\n\n\n### b-button  \u003c-  b-control\n```html\n\u003ca href=\"#\" class=\"b-button\"\u003eКнопка\u003c/a\u003e\n```\n\n\n### b-checkbox  \u003c-  b-control\n * Space OR Enter — for toggle \"checked\"\n * b-checkbox_checked\n * b-checkbox_checked_mixed\n\n```html\n\u003cspan class=\"b-checkbox\"\u003e\n\t\u003cspan class=\"b-checkbox__checkmark\"\u003e\n\t\t\u003cinput name=\"cbx\" type=\"checkbox\"/\u003e\n\t\u003c/span\u003e\n\u003c/span\u003e\n```\n\n\n### b-radio  \u003c-  b-checkbox\n```html\n\u003cspan class=\"b-radio\"\u003e\n\t\u003cspan class=\"b-radio__bubble\"\u003e\n\t\t\u003cinput name=\"radio\" type=\"radio\"/\u003e\n\t\u003c/span\u003e\n\u003c/span\u003e\n```\n\n\n### b-list\n * UP/DOWN arrows — move \"b-list\\_\\_item\\_hover\" between \"b-list\\_\\_item\"\n * b-list_focus\n * b-list_active\n * b-list__item_hover\n\n```html\n\u003cul class=\"b-list\"\u003e\n\t\u003cli class=\"b-list__item\"\u003eitem 1\u003c/li\u003e\n\t\u003cli class=\"b-list__item\"\u003eitem 2\u003c/li\u003e\n\u003c/ul\u003e\n```\n\n\n### b-dropdown  \u003c-  b-control\n * ESC — remove \"expanded\"\n * Space OR Enter — toggle \"expanded\"\n * UP/DOWN arrows — move \"b-dropdown\\_\\_list\\_\\_item\" between \"b-dropdown\\_\\_list\\_\\_item\\_hover\", if before include b-list\n * b-dropdown_expanded\n * b-dropdown__ctrl_focus\n * b-dropdown__ctrl_hover\n * b-dropdown__ctrl_expanded\n * b-dropdown__list_expanded\n * b-dropdown\\_\\_list\\_\\_item\\_hover — if before define b-list\n\n```html\n\u003cdiv class=\"b-dropdown\"\u003e\n\t\u003cdiv class=\"b-dropdown__ctrl\"\u003etext\u003c/div\u003e\n\t\u003cdiv class=\"b-dropdown__list\"\u003e\n\t\t\u003cdiv class=\"b-dropdown__list__item\"\u003eitem 1\u003c/div\u003e\n\t\t\u003cdiv class=\"b-dropdown__list__item\"\u003eitem 2\u003c/div\u003e\n\t\u003c/div\u003e\n\u003c/div\u003e\n```\n\n\n### b-filter\n * b-filter\\_\\_list\\_\\_item\\_filtered — hidden element\n\n```html\n\u003cdiv class=\"b-filter\"\u003e\n\t\u003cinput type=\"text\" class=\"b-filter__input\" /\u003e\n\t\u003cdiv class=\"js-filter-item\"\u003eitem 1\u003c/div\u003e\n\t\u003cdiv class=\"js-filter-item\"\u003eitem 2\u003c/div\u003e\n\u003c/div\u003e\n```\n\n\n\n------------------------------------------\n\n\n\n## API\n\n### Создание описания\n$.bem(className`:String`, methods`:Object`, statics`:Object`);\n * className — название css-класса, для которого описываем поведение\n * methods — методы экземпляра класса\n * statics — статические методы класса\n\n\n### Наследование\n$.bem(className`:String`, extend`:String`, methods`:Object`, statics`:Object`);\n * extend — название того, кого наследуем\n\n\n### Статические методы и свойства\n * .$win`:jQuery` — ссылка на $(window)\n * .$doc`:jQuery` — ссылка на $(document)\n * .lazy`:Boolean = false` — ленивая инициализация\n * .cache`:Boolean = false` — кешировать все выборки\n * .forced`:Boolean = false` — принудительно инициализировать все элементы\n * .live`:Object` — делигируемые события\n * .mods`:Set(hover,focus,press)` — авто-модификаторы (перечисление через пробел)\n * .attrs`:Object` — аттрибуты, которые необходимо выставить DOM-элементу\n\n\n### Свойства класса\n * .self`:BEM` — ссылка на класс, для доступа к статическим методам и свойствам\n * .boundAll`:String` — название методов, через пробел которые нужно привязать к контексту инстанса\n * .debouceAll`:String` — формат записи \"methodName:mSec\"\n * .cache`:Boolean` — кешировать выборки\n * .forced`:Boolean` — инициализировать объект сразу, после его появления\n * .uniqId`:Number` — уникальный модификатор в рамках BEM-элементов\n * .role`:String` — role-атрибут\n * .$el`:jQuery` — ссылка на jQuery-элемент\n * .el`:HTMLElement` — ссылка на DOM-элемент\n * onMod`:Object` — список слушателей, на установку того или иного модификатора\n\n\n### Методы класса\n * .init() — вызывается при инициализация объекта (@protected)\n * .getId()`:Number` — получить уникальный идентификатор\n * .bound(fn`:Function|String`[, arg1[, argsN]])`:Function` — связать функцию с контекстом класса\n * .debounce(fn`:Function|String`[, delay`:Number`])`:Function` — вызов функции будет произведен только один раз, через N ms\n * .throttle(fn`:Function|String`[, delay`:Number`])`:Function` — вызов функции будет произведен только один раз в N ms\n * .hasMod(mod`:String`[, state`:Mixed`])`:Boolean` — проверить наличие модификатора\n * .addMod(mods`:String`[, state`:Mixed`])`:this` — добавить список модификатор, разделитель пробел\n * .delMod(mods`:String`[, state`:Mixed`])`:this` — убрать модификаторы\n * .toggleMod(mod`:String`[, state`:Mixed`]))`:this` — addMod/delMod\n * .$()`:this.$el` — вернет ссылку на элемент\n * .$(selector`:String`)`:jQuery` — найти все элементы соответствующие css-селектору в this.$el\n * .$(__name`:String`)`:jQuery` — найти элементы в соответствии c BEM именованием\n * .$attr(name`:String`)`:Mixed` — получить значение атрибута\n * .$attr(name`:String`, value`:Mixed`)`:this` — изменить атрибут\n * .$attr(attrs`:Object`)`:this` - изменить атрибуты\n * .$attr(name`:String`, null)`:this` — установка атрибута в null равносильно его удалению\n * .$attr(selector`:String`, attrs`:Object`)`:this` — изменить атрибуты для элементов, соответствующих css-селектору\n * .$aria() - тоже самый $attr, только ко всем атрибутам добавляем префикс \"aria-\"\n * .$css(), $prop() — аналогично $attr\n * .on(name`:String`, fn`:String|Function`)`:this` — подписаться на событие, this.$el.bind(name, fn)\n * .on(name`:String`, selector`:String`, fn`:String|Function`)`:this` - слушать событие с конкретных элементов, this.$el.delegate(selecotr, name, fn)\n * .off(name`:String`)`:this` — убрать всех слушателей, this.$el.unbind(name)\n * .off(name`:String`, selector`:String`)`:this` — снять слушателя, с конкретных элементов, this.$el.undelegate(selecotr, name)\n * .hasOn(name`:String`)`:Boolean` — проверить наличие подписки на конкретное событие\n * .onOutside(name`:String`, fn`:String|Function`)`:this` — подписаться на событие, за пределами элемента\n * .offOutside(name`:String`)`:this` — убрать слушателя\n * .trigger(name`:String`[, args`:Array`])`:this` — испустить событие\n * .isDisabled()`:Boolean` — проверить элемент на наличие модификатора disabled\n * .destroy() — уничтожить экземпляр класса\n * .destroy(true) — уничтожить + удалить связанные элемент\n\n---\n\n### Пример работы с onMod\n```js\nonMod: {\n\tsize: {\n\t\tS: function (){ /* set: _size_S */ },\n\t\tM: function (){ /* set: _size_M */ },\n\t\tL: function (){ /* set: _size_S */ },\n\t\t'': function (){ /* remove mod */ }\n\t},\n\n\tsize_XL: function (){}\n\n\tfocus: function (state/**Mixed*/){\n\t\t// (2) after \"*\"\n\t},\n\n\tfocus_yes: function (){\n\t\t// (3) call after \"focus\"\n\t},\n\n\t'*': function (mod/**String*/, state/**Mixed*/){\n\t\t// (1) Call before set modifier\n\t\t// return false, to break\n\t}\n}\n```\n\n---\n\n### onElemMod\n```js\n{\n\t'element': {\n\t\t'modName': function ($el, state, mod, elemName) {\n\t\t\t// ..\n\t\t},\n\n\t\t'*': function ($el, mod, state, elemName) {\n\t\t\t// установка любого модификатор\n\t\t}\n\t},\n\n\n\t// установка любого модификатор, на любой элемент\n\t'*': function ($el, elemName, mod, state) {\n\t\tif (this.isDisabled()) { // блок задизаблен\n\t\t\t// Запрещаем смену модификаторов у элементов\n\t\t\treturn false;\n\t\t}\n\t}\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frubaxa%2Fjquery.bem","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frubaxa%2Fjquery.bem","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frubaxa%2Fjquery.bem/lists"}