Использование модульного шаблона проектирования в Javascript с выбором DOM

Я уже довольно долгое время рассматриваю Модульный шаблон дизайна и нахожу его чрезвычайно полезным, так как он помогает в улучшении обслуживания кода и разделение блоков на модули.

Регулярное использование структуры модуля с помощью jQuery привело к большей части моих приложений/кода, следующих ниже:

(function() {
    var chat = {
        websocket: new WebSocket("ws://echo.websocket.org/"),
        that: this,
        init: function() {
            this.scrollToBottom();
            this.bindEvents();
            this.webSocketHandlers();
        },
        bindEvents: function() {
            this.toggleChat();
            this.filterPeople();
            this.compose();
        },
        elements: {
            indicator: $(".indicator"),
            statusText: $(".status-text"),
            chatHeadNames: $(".people li .name"),
            filterInput: $("#filter-input"),
            msgInput: $("#msg-input"),
            sendBtn: $(".send")
        },
        ...
        ...
        ...
        filterPeople: function() {
          var that = this;
          this.elements.chatHeadNames.each(function() {
              $(this).attr('data-search-term', $(this).text().toLowerCase());
          });
        },
        ...
        ...
        };

        chat.init();
})();

То, что я хотел бы знать, заключается в том, ссылается ли ссылка на все мои элементы на jQuery как на одну переменную chat.elements на хорошую практику?

Одна часть меня говорит, что это действительно хороший способ сразу ссылаться на все ваши селекторы и кэшировать их в переменных, чтобы можно было использовать многократное использование одного и того же элемента с кэшированными переменными (а не с несколькими выборами DOM).

Другая часть меня говорит, что это может быть анти-шаблон, и определенные элементы должны быть выбраны и кэшированы локально, когда это необходимо.

Я использовал подобные структуры повсюду и получил смешанные ответы о коде, но ничего сплошного. Любая помощь будет оценена по достоинству. Спасибо!

Ответы

Ответ 1

Кэширование селекторов - это хорошо. Подвешивание к ним - хорошая идея. Это повышает производительность за многократное обращение к DOM за одно и то же. Вышеупомянутый код очень похож на код BackboneJS и MarionetteJS.

У меня есть некоторые предупреждения для вас:

  • Этот шаблон может вызвать утечку памяти. Рассмотрим случай, когда вы нарушаете subview, но вы держите ссылку на что-то, что его выбрало. Это называется свисающим указателем. Вид не исчезнет. Все привязки останутся. События будут продолжать огонь за кулисами.
  • В конечном итоге вы столкнетесь с ошибкой, когда вы решили повторно отобразить часть своего экрана. Затем требуется очистка всех привязок, и вам нужно не забывать удалять и выбирать. Если вы этого не сделаете, вы почти наверняка столкнетесь с проблемами, когда вы задаетесь вопросом, почему событие действительно стреляет, но на экране ничего не происходит... (это будет потому, что это происходит из экрана, к тому элементу, который вы пробовали для удаления, который все еще существует... sorta).
  • Текущий способ запроса элементов вызывает поиск по всей странице. Посмотрите https://api.jquery.com/find/. Если вы кешируете один селектор и затем выполняете поиск внутри этого селектора, он может немного повысить производительность.

Ответ 2

  • Я думаю, Если в модуле чата есть селекторы только для его детей, тогда это хороший шаблон. Как:
<div id="chat-module">
  <div class="indicator">...</div>
  <div class="status-text">...<div>
  ...
</div>
<script src="and your chat module.js"></script>
// your chat module selecting .indicator:
// $('#chat-module.indicator')
  • Также добавьте функцию выключения к вашему модулю. Таким образом, когда вы удаляете его из представления (как в одностраничном приложении), вы можете свести на нет свои селекторы и отсоединить обработчики событий, например: delete this.elements.indicator и код удаления события.

Существуют и другие/лучшие шаблоны для этого, например, когда пользователь что-то набирает, вы запускаете событие и захватываете это событие в своем модуле. Отделить интерфейс и код.

Ответ 3

Я согласен с Parris, что кеширующие селектора хороши. В нашем проекте мы используем DI и шаблон Facade. Эта структура имеет json configure на всякий случай, если новый модуль будет другой структурой.

Я думаю, что вы больше всего:

  • отправить настройки конфигурации;
  • только кеш-кеш elems;
  • Элементы кэширования кеширования в params.classes;
  • отложить общую функцию в помощниках; Например:

    (function() {
    var chat = {
        websocket: new WebSocket("ws://echo.websocket.org/"),
        that: this,
        params: {
            elems: {
                module: '.container',
                indicator: ".indicator",
                statusText: ".status-text",
                chatHeadNames: ".people li .name",
                filterInput: "#filter-input",
                msgInput: "#msg-input",
                sendBtn: ".send"
            }
            classes: {
              dinamicInput: '.dinamicInput'
            }
        },
        init: function(params) {
            opts = $.extend(true, $.extend(true, {}, that.params), params);
            that.initElementsForModule(that.elements, that.params.elems );
            this.scrollToBottom();
            this.bindEvents();
            this.webSocketHandlers();
        },
        bindEvents: function() {
            this.toggleChat();
            this.filterPeople();
            this.compose();
        },
    
        initElementsForModule = function (elements, identifiers) {
            var $module,
                prop;
    
            for (prop in identifiers) {
                if (identifiers.hasOwnProperty(prop) && prop !== "module") {
                    elements["$" + prop] = $module.find(identifiers[prop]);
                }
            }
    
        },
    
        elements: {
            module: null,
            indicator: null,
            statusText: null,
            chatHeadNames: null,
            filterInput: null,
            msgInput:null,
            sendBtn: null
        },
        ...
        ...
        ...
        filterPeople: function() {
          var that = this;
          this.elements.chatHeadNames.each(function() {
              $(this).attr('data-search-term', $(this).text().toLowerCase());
          });
        },
        ...
        ...
        };
    
        chat.init();
     })();