Как распутывать лапшу, не впадая в депрессию
Эта статья не про ваши сладкие интерфейсы на реакте, ангуляре или что вы там используете? Это статья про те ситуации, когда у вас есть кучка jQuery лапши. Нет, пусть это будут горы jQuery лапши, завернутой во вьюшки бэкбона.В статье используется библиотека Backbone.View.Elements
Проблема первая: маловыразительные селекторыВсе мы видели лапшу, все мы знаем: лапша в JSе — наверно и в верстке не все хорошо. А раз все так, то код, скорее всего, кишит непонятными манипуляциями с домом. Читать такой код сложно, ведь надо, не упуская мысли автора о том, что здесь вообще происходит, держать в уме кучку невнятных названий для элементов. Итак, давайте придадим коду немножко выразительности: _selectors: function () { return { elemName: '.block__elem-name' }; } Сложим все селекторы в одном месте и дадим понятное название элементам, для выбора которых они нужны. Выбирать мы их, кстати, будем вот так: this._elem ('elemName'); вмсето this.$('.block__elem-name'); В нашем случае вы можете сказать, что это мало добавило выразительности, но не забывайте, что у вас, скорее всего, не проект, использующий БЭМ для именования классов, а сладко пахнущие сверх семантичные селекторы вида «div > tr.row[data-active=«true»] a.red-Button» для кнопок «купить».Помимо возможности выбрать элемент внутри нашей вьюшки, мы также получили возможность получить сам селектор по имени:
this._selector ('elemName'); Это тоже бывает нужно.Еще одно преимущество — если изменится верстка, то нам надо будет изменить селектор только в одном месте, потому что мы уменьшили дублирование кода.
Проблема вторая: хранение элементов Знаете, бывает вот так: $(«div > tr.row[data-active=«true»] a.red-Button»).blahBlah (); , а через 10 строк вот так: $(«div > tr.row[data-active=«true»] a.red-Button»).anotherBlahBlah (); Отодрав ладонь от лица, вы вынесете это в переменную var $buyButton = $(«div > tr.row[data-active=«true»] a.red-Button»); ой нет, у вас же Backbone — вынесете в свойство this._$buyButton = this.$(«div > tr.row[data-active=«true»] a.red-Button»); или вы уже подключили Backbone.View.Elements? this._$buyButton = this._elem («buyButton»); На самом деле не стоит — _elem и так все кеширует, так что просто this._elem («buyButton»); Кеширует, говорите? А что, если все изменится? Да, мы тоже слышали, что в программировании две проблемы. Поэтому this._findElem ('elemName'); ищет без использования кеша this._dropElemCache («elemName»); почистит кеш для конкретного элемента, а this._dropElemCache (); отчистит весь ваш кеш до блеска, когда вы поймете, что время пришло. Например, после рендеринга.Глобальные элементы А еще мы завернули в jQuery наиболее часто используемые элементы, чтобы не делать это больше одного раза в приложении. Встречайте: this._$window; this._$body; this._$document; Проблема третья: императивные стили Вроде бы целый язык есть, чтобы стили описывать, но нет — то и дело в лапше можно найти красители: $(«div > tr.row[data-active=«true»] a.red-Button»).css ({color: «magenta»}); Скорее поперчите все декларативностью и хорошенько перемешайте CSS: .button_active { color: magenta; } А уж об манипуляции классами мы позаботились. Сначала обозначим все классы в одном месте: _classes: function () { return { activeButton: 'button_active' }; } А потом, хотите — добавляйте класс this._addClass («activeButton», «buyButton»); хотите — удаляйте: this._removeClass («activeButton», «buyButton»); хотите — переключайте: var condition = ! Math.round (Math.random ()); this._toggleClass («activeButton», «buyButton», condition); Можно получить селектор, если класс уже описан: this._selector («activeButton»); // returns ».button_active» , а можно и элементы поискать: this._elem («activeButton»); Только не забывайте про кеш, ведь активная кнопка наверняка меняется this._findElem («activeButton»); Проблема четвертая: когда всё сложно Бывает, селекторы и классы формируются динамически: var id = 5, state = «highlighted»; $(».item[data-id=» + id + »]»).addClass («item_state_» + state); Тут в дело вступают сложные селекторы: _classes: function () { return { itemInState: 'item_state_%s' }; },
_selectors: function () { return { itemById: '.item[data-id=%s]' }; } Тогда справедливо будет следующее: this._class («itemInState», «highlighted»); // вернет «item_state_highlighted» this._selector («itemInState», «highlighted»); // вернет ».item_state_highlighted» this._selector («itemById», 5); // вернет ».item[data-id=5]» А манипуляция описанная выше будет выполняться следующим образом: var id = 5, state = «highlighted»; this._addClass ([«itemInState», state], [«itemById», id]); Класс item_state_highlighted добавится элементу, найденному по селектору .item[data-id=5]Терминальная сложность селекторов _classes: function () { return { item: 'item_%(mod)s_%(value)s' }; } Каждому месту свое имя this._elem («item», { mod: «state», value: «focused» }); Найдет jQuery коллекцию по селектору ».item_state_focused«Проблема пятая: получение данных Немножко сахара для дата атрибутов. this._data; Хранит данные корневого элемента вью. Так что, если у вас есть div
на котором инициализирована вью this._data[«someIds»]; // вернет массив [5,6,7] А если данные хранятся в конкретном элементе, то вам поможет this._getElemData («elemName», «someIds»); Для того, чтобы получить все данные: this._getElemData («elemName»); // вернет {someIds: [5,6,7]} Про установку и использование GitHub: github.com/backbonex/backbone.view.elementstodomvc с использованием Backbone.View.Elements и без него