【问题标题】:Knockout.js get dom object associated with dataKnockout.js 获取与数据关联的 dom 对象
【发布时间】:2012-04-24 23:45:49
【问题描述】:

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

例子:

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

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

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

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

【问题讨论】:

    标签: jquery dom knockout.js


    【解决方案1】:

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

    【讨论】:

    • 非常感谢!这很好用!感谢您对 jQuery 操作的提醒。我在特定行上使用自动完成功能,所以我认为我不能通过 ko 做到这一点。很好的解决方案
    • 对自动完成padawan使用自定义绑定。 :P 在使用 ko 开发 3 个月后我学到的一件事:使用自定义绑定和 jquery/jquery ui 的东西。
    • 我从事淘汰赛已经很多年了,并且不知道事件参数 - 太棒了!谢谢
    【解决方案2】:

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

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

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

    然后 getDomObject() 看起来像:

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

    【讨论】:

    • 恕我直言,由于 yuvalr80 所说的原因,这个答案更加完整。
    • 这个答案是我所需要的,但对于原始问题来说,接受的答案更好。不过,也感谢您发布此答案,这正是我所需要的。跨越 MVVM 的界限并不疯狂,但我只需要一种有效的方法来滚动一个项目以查看,并且不想为此而为列表中的每个对象添加额外的 observable。
    • 它可以工作,但传递 ID,然后通过该 ID 获取 DOM。它打破了一些规则。任何非 ID 解决方案将不胜感激。
    • 我同意 Andrew Steitz - 这应该是公认的答案。这是一个更全面的解决方案。
    • 注意不要在 KO 绑定发生之前运行 jQuery 表达式,否则不会设置 DOM 元素 ID - 我按照this 回答添加了一个afterBind() 方法。
    【解决方案3】:

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

    创建自定义绑定,例如:

    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。

    【讨论】:

    • 我做过类似的事情,效果很好!感谢您的帖子
    【解决方案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");
      }
    }
    

    希望这会有所帮助!

    【讨论】:

    • 我希望我可以多次投票,因为我已经多次需要这个并且我多次遇到你的答案!
    【解决方案5】:

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

     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 元素。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-02
      • 1970-01-01
      • 2022-11-09
      • 2015-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多