Подтвердить что ты не робот

Backbone.js - С учетом элемента, как мне получить представление?

Я создал кучу Backbone.js просмотров. Каждое представление имеет связанный элемент (view.el).

Учитывая элемент на странице - вне контекста представления - какой лучший способ получить представление для элемента?

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

Один из способов - назначить представление элементам данных, но мне интересно, пропустил ли я что-нибудь умнее:

var myview = BackBone.View.extend({
    initialize: function(options) {
        $(this.el).data('view', this);
        ...
    }
});

(Я использую Backbone с jQuery 1.5.)

4b9b3361

Ответ 1

Я только что написал плагин jQuery для этого. Он также использует метод .data().

Регистрация:

Я обернул/проксировал метод Backbone View setElement, чтобы прикрепить необходимые данные к свойству представления $el.

Регистрация выполняется за кулисами:

$(myViewsEl).backboneView(myView);

индексирование:

Плагин пересекает иерархию DOM (используя .closest()), пока не найдет элемент с требуемым вводом данных, то есть элемент DOM со связанным представлением:

var nearestView = $(e.target).backboneView();

Кроме того, мы можем указать, какой тип Backbone View мы хотим получить, продолжая иерархию, пока не найдем экземпляр соответствующего типа:

var nearestButtonView = $(e.target).backboneView(ButtonView);

Пример JSFiddle:

Здесь можно найти .

Примечания:

Надеюсь, я прав, думая, что здесь нет утечек памяти; "Unlink" выполняется, если setElement вызывается во второй раз, и поскольку удаление элемента вида вызывает .remove() по умолчанию, что также разрушает все данные, Дайте мне знать, если вы думаете по-другому.

Код плагина:

(function($) {

    // Proxy the original Backbone.View setElement method:
    // See: http://backbonejs.org/#View-setElement

    var backboneSetElementOriginal = Backbone.View.prototype.setElement;

    Backbone.View.prototype.setElement = function(element) {
        if (this.el != element) {
            $(this.el).backboneView('unlink');                    
        }

        $(element).backboneView(this);    

        return backboneSetElementOriginal.apply(this, arguments);
    };

    // Create a custom selector to search for the presence of a 'backboneView' data entry:
    // This avoids a dependency on a data selector plugin...

    $.expr[':'].backboneView = function(element, intStackIndex, arrProperties, arrNodeStack) {
        return $(element).data('backboneView') !== undefined;        
    };

    // Plugin internal functions:

    var registerViewToElement = function($el, view) {
        $el.data('backboneView', view);
    };

    var getClosestViewFromElement = function($el, viewType) {
        var ret = null;

        viewType = viewType || Backbone.View;

        while ($el.length) {
            $el = $el.closest(':backboneView');
            ret = $el.length ? $el.data('backboneView') : null;

            if (ret instanceof viewType) {
                break;
            }
            else {
                $el = $el.parent();
            }           
        }

        return ret;                
    };

    // Extra methods:

    var methods = {

        unlink: function($el) {
            $el.removeData('backboneView');        
        }

    };

    // Plugin:

    $.fn.backboneView = function() {
        var ret = this;
        var args = Array.prototype.slice.call(arguments, 0);

        if ($.isFunction(methods[args[0]])) {
            methods[args[0]](this);                        
        }
        else if (args[0] && args[0] instanceof Backbone.View) {
            registerViewToElement(this.first(), args[0]);                
        }
        else {
            ret = getClosestViewFromElement(this.first(), args[0]);
        }

        return ret;        
    }        

})(jQuery);

Ответ 2

Каждое представление может регистрироваться для событий DOM. Таким образом, каждое представление с типом интересующего вас элемента должно регистрироваться для события DOM, а затем назначать функцию ответа на события, которая делает то, что вы хотите. Если вам нужно СУХОЙ вещи, используйте методы mixin для смешивания в функции.

Я думаю, возможно, это решение проще, чем вы могли себе представить. Просто позвольте представлениям делать то, что они предназначены.

Ответ 3

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

http://www.timdown.co.uk/jshashtable/

Ответ 4

Поскольку у каждого представления есть ссылка на модель, ее отображение, то я бы сделал, это присвоить id модели связанному с представлением элементу (надеюсь, на него не влияют изменения по внешнему событию). Также убедитесь, что модель имеет ссылку на ее представление. Затем эти модели хранятся в коллекции Backbone.

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

Ответ 5

Я использую метод, основанный на Ed решении, но для него не требуется использование jQuery. Он выполняет две функции:

  • Он устанавливает атрибут data-backbone-view в корневых элементах всех представлений. Это удобно при просмотре дерева DOM в отладчике. Вы можете сразу увидеть, какие элементы связаны с представлениями. Вы также можете использовать селектор CSS [data-backbone-view], чтобы найти элементы, которые являются корнями представлений Backbone.

  • Он добавляет свойство backboneView к каждому корневому элементу представления. Затем можно перейти от элемента DOM к представлению, просмотрев свойства элемента DOM.

Я включаю это только тогда, когда я отлаживаю. Вот код:

var originalSetElement = Bb.View.prototype.setElement;

Bb.View.prototype.setElement = function setElement(element) {
  if (this.el && this.el !== element) {
    delete this.el.backboneView;
  }

  element.backboneView = this;
  element.setAttribute("data-backbone-view", "true");

  return originalSetElement.apply(this, arguments);
};