Вопрос по dom, jquery – Knockout.js получает объект dom, связанный с данными

47

Я работаю с knockout.js для создания динамических списков и пытаюсь выяснить, как я могу получить объект DOM, связанный с объектом в моем наблюдаемом массиве. В частности, я хочу получить JQuery для строки.

Пример:

<code><ul data-bind="foreach: Item">
    <li data-bind="events: {click: getDomObject}, text: 'text: ' + text">
    </li>
</ul>
</code>

вgetDomObject функция, я хотел бы иметь возможность получить конкретный<li></li> DOM объект, так что я могу сделать некоторые манипуляции с JQuery с ним.

Я думал о добавленииid член Item ViewModel, а затем добавить идентификатор в качестве идентификатора html позиции и затем выбрать на основе этого, но я чувствую, что должен быть более простой способ.

Как правильно ссылаться на динамический HTML, сгенерированный knockout.js?

Ваш Ответ

5   ответов
4

напоминающему использование Backbone.js ссылок el и $ el.

в вашей ViewModel:

var myViewModel = function(){
  var self = this;

  //html element
  self.el = ko.observable();

  //jquery wrapped version
  self.$el = ko.observable();
}

в HTML (например, элемент списка):

<!-- left side is the name of the handler, right side is name of the observable -->
<li class="myclass" data-bind="el: el, $el: $el"></li>

в bindingHandlers (показывая все возможные аргументы для init):

ko.bindingHandlers.el = {
  init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    var value = valueAccessor();
    //assign value to observable (we specified in html)
    value(element);
  }
};

ko.bindingHandlers.$el = {
  init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    var value = valueAccessor();
    //here we first create a jQuery object by using $(myelem)
    //before updating observable value
    value($(element).first());
  }
};

Например, тогда вы можете использовать $ el как:

var myViewModel = function(){
  var self = this;

  //plain DOM element reference
  self.el = ko.observable();

  //jquery object reference
  self.$el = ko.observable();

  self.myFunction = function() {
    console.log(self.$el().html());
    self.$el().addClass("myCssClass");
  }
}

Надеюсь это поможет!

4

 ko.bindingHandlers.value.preprocess = function(val, name, cb) {
    /* every time I set a data-bind="value: xxxx" with an 
     * observable xxxx add also a data-bind="domElement: xxxx" */
    cb('domElement', val );
    return val;
}

ko.bindingHandlers.domElement = {
    /* For each data-bind="domElement: xxxx" add an extension "element" */
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) { 
      valueAccessor().extend({element: element });
    }
  };

ko.extenders.element = function (target, element) {
    /* element extension add el and $el to observable xxxx */
    target.el = element;
    target.$el = $(element);
} 

Теперь у вас есть yourobservable. $ El и yourobservable.el, которые связываются с jquery и элементом DOM.

66

the item that this event belongs to - like the entry of an observable array that you're rendering with the foreach binding ("Item" in your case).

And, an event object, that provides you with more information about the actual event. This object contains the DOM element that got clicked on (key "target"):

getDomObject = function(item, event) {
    var $this = $(event.target);
    // ...
}

Просто примечание: не смешивайте нокаут и нативные манипуляции с JQuery DOM - если вы можете достичь того же результата с помощью умных привязок нокаутов, я бы рекомендовал пойти на это.

А вот простая демонстрация:http://jsfiddle.net/KLK9Z/213/

var Item = function(color) {
  this.color = String(color);
  this.setTextColor = function(item, event) {
    $(event.target).css('background', color);
  };
};

ko.applyBindings(new function() {
  this.Items = ko.observableArray([
    new Item('red'),
    new Item('blue'),
    new Item('green')
  ]);
}());
li {
  padding: 2px 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.0.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<ul data-bind="foreach: Items">
  <li>
    <button data-bind="click: setTextColor, text: 'Color: ' + color"></button>
  </li>
</ul>

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded joe_coolish
Error: User Rate Limit Exceeded
20

$(event.target) Решение является хорошим, если оно связано с уже происходящим событием, в котором элемент DOM элемента находится в цели. Но иногда у вас нет целевого элемента из-за отсутствия события (например, вы хотите прокрутить список до элемента, который не был задан пользователем).

В этом случае вы можете присвоить атрибуту id элемента DOM элемента уникальное значение, которое содержит идентификатор элемента:

<li data-bind="attr: {id: 'item_' + id}">

и тогда getDomObject () выглядит так:

getDomObject = function(item) { return $("#item_" + item.id); }
Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededthisError: User Rate Limit ExceededafterBind()Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
7

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

Создайте пользовательскую привязку, такую как:

ko.bindingHandlers.scrollTo = {
    update: function(element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        if (value) {
            var scrollParent = $(element).closest("div");
            var newTop = $(element).position().top + scrollParent.scrollTop();
            scrollParent.scrollTop(newTop);
        }
    }
};

использование заключается в следующем:

<li data-bind="scrollTo: $parent.scrollTo() && $parent.scrollTo().id == id">

В приведенном выше случае $ parent - это моя модель просмотра. У меня есть наблюдаемый объект, который содержит уникальный идентификатор. Каждый раз, когда я устанавливаю этот объект scrollTo (), список прокручивается до этого элемента.

Обратите внимание, что мой код предполагает, что родительский DIV LI имеет полосу прокрутки (переполнение: авто / прокрутка). Вы можете приспособиться к вашим потребностям, возможно, использовать класс для родителя и использовать его для своего селектора jQuery, или чтобы сделать его очень гибким, вы могли бы передать селектор через параметры привязки данных ... для меня этого было достаточно, так как Я всегда использую div для своих прокручиваемых разделов.

Error: User Rate Limit Exceeded joe_coolish

Похожие вопросы