【问题标题】:Backbone Marionette CompositeView "Event Zombie"骨干木偶 CompositeView “事件僵尸”
【发布时间】:2012-05-30 03:44:37
【问题描述】:

我有一个使用 Backbone Marionette CompositeView 创建的相当简单的表。此表的唯一要求是它显示数据并允许用户通过单击标题行对其进行排序。对表格进行排序时,用于对标题列进行排序的列用类标记,以允许使用 CSS 显示箭头(例如 'class="sort asc"')。

问题是:当点击标题行时,传递给回调(通过 event.target)的元素不是 DOM 上的表的一部分。相反,使用 Chrome 的调试工具,似乎目标元素实际上是模板脚本块的一部分,而不是用户实际看到的元素。

我现在最好的解决方法是通过从模板中的克隆检索元素来查找实际附加到 DOM 的元素。

这是复合视图代码(借自 Derick Bailey 的 Fiddle 示例之一):

// The grid view
var GridView = Backbone.Marionette.CompositeView.extend({
    tagName: "table",
    template: "#grid-template",
    itemView: GridRow,

    events: {
        'click th': 'doSort'
    },

    doSort: function(event) {
        var target = $(event.target);
        this.collection.sortByField(target.data('sortby'));

        target.parent('tr').find('.sort').removeAttr('class');
        target.addClass('sort ' + this.collection.sortdir);
        debugger; // NOTE: no change to elements in the DOM. WTH?

        target = this.$('[data-sortby=' + target.data('sortby') + ']');
        target.parent('tr').find('.sort').removeAttr('class');
        target.addClass('sort ' + this.collection.sortdir);
        debugger; // NOTE: DOM updated.
    },

    appendHtml: function(collectionView, itemView) {
        collectionView.$("tbody").append(itemView.el);
    }
});

模板也很简单:

<script id="grid-template" type="text/template">
    <thead>        
        <tr>
            <th data-sortby="username">Username</th>
            <th data-sortby="fullname">Full Name</th>
        </tr>
    </thead>
    <tbody></tbody>
</script>

可以在这里找到 Derek 的原始演示 Fiddle 的一个分支,用于演示该问题: http://jsfiddle.net/ccamarat/9stvM/14/

我有点绕。我的问题是,我似乎产生了某种僵尸视图;这是一个 jQuery/Backbone/Underscore 错误,还是我只是把这一切都搞错了?

** 编辑 ** 这是显示两个元素的不同父层次结构的控制台输出:

console.log(target, targetb):
    [<th data-sortby="username" class="sort asc">Username</th>] [<th data-sortby="username">Username</th>]

console.log(target.parents(), targetb.parents()):
    [<tr>…</tr>, <thead>…</thead>] [<tr>…</tr>, <thead>…</thead>, <table>…</table>, <div id="grid">…</div>, <body>…</body>, <html>…</html>]

console.log(target === targetb):
    false

【问题讨论】:

  • 您能更具体地说明问题吗?您以非常详细的方式提到了几个潜在的问题,但随后只问了一个非常简短的问题,没有详细信息,关于僵尸视图。您要解决哪些问题?为什么你认为你有僵尸观点?你在哪里看到什么僵尸?
  • 另外 - 我已经在最新版本的 Chrome 中运行了你的示例小提琴,它工作正常。您说DOM尚未更新的评论......当我运行它时,它已经更新了。您使用的是什么浏览器/版本?
  • 如果听起来问题不止一个,我解释自己的工作做得很糟糕。唯一的问题是我所说的僵尸视图。我之所以称之为它,是因为至少在我的设置中,在第一个断点处更新的元素(使用 event.target)与第二个断点处的元素(使用 this.target)not 相同。 $el.find())。我正在使用最新版本的 Chrome 进行测试,并且已经能够在两台不同的机器上复制两次。
  • 我更新了我的 Fiddle 来测试这两个元素是否相等,而在我的设置中它们不是。在这里:jsfiddle.net/ccamarat/9stvM/13
  • 另外,我用控制台输出更新了上面的帖子,显示这两个元素具有不同的父层次结构。

标签: jquery backbone.js underscore.js marionette


【解决方案1】:

我没有看到任何僵尸视图的证据。

我创建了一个代码分支并添加了一些额外的日志记录来检查视图实例,但我没有看到任何僵尸。每次都使用相同的 GridView 实例。每次排序时,子视图都会正确关闭。

http://jsfiddle.net/derickbailey/hadbf/4/

您看到的问题很可能是使用target = $(e.target)targetb = this.$(...) 引起的。这是两个非常不同的语句,它们来自两个非常不同的 DOM 元素来源。

target = $(e.target) 的首次使用是直接从 DOM 运行。您正在被点击的目标上运行一个选择器,它只是将该 DOM 元素包装在一个 jQuery 选择器对象中。

targetB = this.$(...) 的第二个用途是使用主干视图的$el 进行查找:this.$el.find("..."),它将根据视图的 EL 返回结果。视图的 $eL 恰好包含属于 DOM 的元素。但是 $el 与 e 事件不是同一个对象,所以你永远不会以 target === targetb 为真。

...除非我完全误解了这个问题(在这一点上似乎很有可能),否则我认为这里没有问题。

【讨论】:

  • 你的小提琴让我想到了当sort()被调用时会发生什么——底层集合被改变,触发所有子视图的关闭——这是有道理的。但是,我没想到它会重置标题行,但这正是发生的事情。 sort() 被调用后,event.target 不再指向 DOM 上的元素,因为 render() 操作调用了 'renderModel()',它从模板重新生成视图,在此过程中破坏了 event.target
  • 所以我创建了一个孤立的参考,而不是僵尸视图。我可以通过继承 CollectionView 而不是复合视图、覆盖 initialize() 函数并手动读取模板来解决此问题。感谢您的宝贵时间!
  • 我现在明白了……这是因为 CompositeView 从 CollectionView 扩展而来,而且 CollectionView 有一个内置的事件处理程序,当集合重置时,它通过调用 .render 方法重新渲染。对集合进行排序会重置集合(我认为),因此整个复合视图会重新呈现。您可以覆盖复合视图的 initialEvents 方法以更改该行为:derickbailey.github.com/backbone.marionette/docs/… 链接指向 CollectionView,但只需将该方法添加到您的 CompositeView 即可覆盖。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-13
  • 2014-03-27
  • 1970-01-01
  • 2014-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多