2012-04-12 71 views
46

我正在使用knockout.js来构建动态列表,并且试图弄清楚如何获取与可观察数组中的对象关联的DOM对象。具体而言,我想获得一行jQuery。Knockout.js获取与数据相关联的dom对象

例子:

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

,我希望能够得到具体<li></li> DOM对象,以便我可以做一些jQuery的操纵它。

我想过在项目ViewModel中添加一个id成员,然后添加该id作为该项目的html id,然后选择基于该项目,但我觉得应该有一个更简单的方法。

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

回答

64

像点击这样的事件处理程序传递了两个参数。那是a)这个事件所属的项目 - 就像你用foreach绑定(你的案例中的“Item”)呈现的可观察数组的条目。和b)一个事件对象,为您提供有关实际事件的更多信息。这个对象包含得到点击(重点“目标”)的DOM元素:

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

只是注意:不要混合淘汰赛和本地jQuery的DOM操作 - 如果你能达到与巧妙的淘汰赛绑定相同的结果,我会建议去那个。

这里是一个简单的演示:http://jsfiddle.net/KLK9Z/213/

+0

非常感谢!这很好用!感谢有关jQuery操作的负责人。我在特定的行上使用了自动完成功能,所以我认为我不能通过ko来完成。伟大的解决方案 – 2012-04-12 16:31:11

+0

使用自动完成padawan的自定义绑定。 :P在与ko开发3个月后学到了一件事:使用jquery/jquery ui东西的自定义绑定。 – 2013-02-19 02:02:41

+0

我曾与淘汰赛的年龄,并没有意识到事件参数 - 辉煌!谢谢 – 2013-08-08 04:05:41

20

$(event.target)的解决方案是好的,如果是涉及到一个已经发生的事件进行该产品的DOM元素为目标。但有时你没有目标项目,因为没有事件(例如 - 你想滚动列表到用户未指示的项目)。

在这种情况下,您可以给项目的DOM元素的id属性,它包含项目ID的唯一值:

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

,然后getDomObject()看起来像:

getDomObject = function(item) { return $("#item_" + item.id); } 
+0

恕我直言,这个答案是完全正确的原因yuvalr80陈述。 – 2012-09-17 19:08:55

+0

这个答案是我所需要的,但接受的答案对原始问题更好。感谢您张贴这个答案,但是,正是我所需要的。对于跨越MVVM的界限并不着迷,但我只是需要一种有效的方式来滚动项目以查看,并且不希望为列表中的每个对象添加额外的可观察项。 – eselk 2013-02-18 03:14:12

+1

它的工作原理是传递ID,然后通过该ID获取DOM。它打破了一些规则。任何非ID解决方案将不胜感激。 – 2013-06-11 13:08:52

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"> 

在上述情况下,$父是我的视图模型。我有一个可观察的对象,其中包含一个唯一的ID。每次我设置scrollTo()对象时,列表都会滚动到该项目。

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

+0

我做了类似的事情,效果非常好!感谢这篇文章 – 2013-02-18 21:10:58

1

我有类似的问题。我想出了一个类似于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(显示所有可能的参数初始化):

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

希望这有助于!

1

我的解决方案(适用于 “价值” 的结合)

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。$ E1和yourobservable.el结合到jQuery和DOM元素。