jQuery Knockout.js 获取与数据关联的 dom 对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10126812/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 08:51:31  来源:igfitidea点击:

Knockout.js get dom object associated with data

jquerydomknockout.js

提问by joe_coolish

I'm working with knockout.js to build dynamic lists and I'm trying to figure out how I can get the DOM object associated with an object in my observable array. Specifically I want to get the jQuery for a row.

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

Example:

例子:

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

in the getDomObjectfunction, I would like to be able to get the specific <li></li>DOM object so that I can do some jQuery manipulation with it.

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

I've thought about adding an idmember to the Item ViewModel and then add the id as the line item's html id and then select based on that, but I feel that there should be an easier way.

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

What is the proper way to reference the dynamic HTML generated by knockout.js?

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

回答by Niko

Event handlers like click get passed two arguments. That is

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

  1. 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).

  2. 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);
        // ...
    }
    
  1. 此事件所属的项目 - 就像您使用 foreach 绑定(在您的情况下为“项目”)呈现的可观察数组的条目。

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

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

Just a note: Don't mix knockout and native jQuery DOM manipulations - if you can achieve the same result with clever knockout bindings, I would recommend going with that.

请注意:不要混合使用淘汰赛和本机 jQuery DOM 操作 - 如果您可以通过巧妙的淘汰赛绑定获得相同的结果,我建议您使用它。

And here is a simple demo: http://jsfiddle.net/KLK9Z/213/

这是一个简单的演示: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>

回答by yuvalr80

The $(event.target)solution is good if it is related to an already occurring event in which the item's DOM element is at target. But sometimes you don't have the targeted item because there is no event (for example - you want to scroll a list to an item that was not gestured by the user).

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

In such case you can give the item's DOM element id attribute a unique value that contains the item id:

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

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

and then getDomObject() looks like:

然后 getDomObject() 看起来像:

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

回答by eselk

To add yet a 3rd option, also for cases where you don't have an event to work with (if you have an event, the accepted answer is best/optimized).

添加第三个选项,也适用于您没有事件可以处理的情况(如果您有事件,则接受的答案是最佳/优化的)。

Create a custom binding such as:

创建自定义绑定,例如:

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

usage is as follows:

用法如下:

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

In the above case, $parent is my View Model. I have an observable object which contains a unique ID. Anytime I set that scrollTo() object, the list scrolls to that item.

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

Note that my code assumes the parent DIV of the LI has the scrollbar (overflow:auto/scroll). You can adjust for your needs, possibly use a class on the parent and use that for your jQuery selector, or to make very flexible you could pass in the selector via your data-bind options... for me, this was enough, as I always use divs for my scrollable sections.

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

回答by Murat Ozgul

I had a similar problem. I come up with a solution resembling Backbone.js use of el and $el references.

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

in your ViewModel:

在您的 ViewModel 中:

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

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

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

in html (for example list element):

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

in bindingHandlers (showing all possible arguments to init):

在 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());
  }
};

For example, then you can use $el like:

例如,你可以像这样使用 $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");
  }
}

Hope this helps!

希望这可以帮助!

回答by Emiliano Bruni

My solution (valid for "value" binding)

我的解决方案(对“值”绑定有效)

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

Now you have yourobservable.$el and yourobservable.el which bind to jquery and DOM element.

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