50

我正在使用 knockout.js 构建动态列表,并且试图弄清楚如何获取与我的可观察数组中的对象关联的 DOM 对象。具体来说,我想连续获取 jQuery。

例子:

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

getDomObject函数中,我希望能够获取特定的<li></li>DOM 对象,以便可以对它进行一些 jQuery 操作。

我曾想过id在Item ViewModel中添加一个成员,然后将id添加为line item的html id,然后在此基础上进行选择,但我觉得应该有更简单的方法。

引用由 knockout.js 生成的动态 HTML 的正确方法是什么?

4

5 回答 5

67

像 click 这样的事件处理程序传递了两个参数。那是

  1. 此事件所属的项目 - 就像您使用 foreach 绑定(在您的情况下为“项目”)呈现的可观察数组的条目。

  2. 并且,一个事件对象,它为您提供有关实际事件的更多信息。该对象包含被点击的 DOM 元素(键“目标”):

    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>

于 2012-04-12T15:42:10.243 回答
20

如果$(event.target)解决方案与项目的 DOM 元素位于目标的已经发生的事件相关,则它是很好的解决方案。但有时您没有目标项目,因为没有事件(例如 - 您想将列表滚动到用户未使用手势的项目)。

在这种情况下,您可以为项目的 DOM 元素 id 属性赋予一个包含项目 id 的唯一值:

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

然后 getDomObject() 看起来像:

getDomObject = function(item) { return $("#item_" + item.id); }
于 2012-08-22T09:24:03.057 回答
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 是我的视图模型。我有一个包含唯一 ID 的可观察对象。每当我设置该 scrollTo() 对象时,列表都会滚动到该项目。

请注意,我的代码假定 LI 的父 DIV 具有滚动条(溢出:自动/滚动)。您可以根据需要进行调整,可能在父级上使用一个类并将其用于您的 jQuery 选择器,或者为了非常灵活,您可以通过数据绑定选项传入选择器......对我来说,这就足够了,因为我总是将 div 用于我的可滚动部分。

于 2013-02-18T03:49:38.607 回答
5

我有一个类似的问题。我想出了一个类似于 Backbone.js 使用 el 和 $el 引用的解决方案。

在您的视图模型中:

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");
  }
}

希望这可以帮助!

于 2015-12-29T09:45:26.047 回答
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);
} 

现在你有了绑定到 jquery 和 DOM 元素的 yourobservable.$el 和 yourobservable.el。

于 2017-11-17T10:50:10.230 回答