带有“afterAdd”的 Foreach 绑定会导致整个模板在插入时再次绘制

Foreach binding with 'afterAdd' causes the whole template to draw again on insertions

本文关键字:插入 绘制 afterAdd Foreach 绑定 带有      更新时间:2023-09-26

每当将新项目添加到列表中时,我都会尝试自动滚动页面的内容。

起初,我尝试在foreach绑定中使用afterAdd,因为它似乎是我想要的。所以我做了这样的事情:

<ul data-bind="foreach: { data: contents, 
                          afterAdd: function(e) { e.scrollIntoView(false); } }">
    <li data-bind="text: field"></li>
</ul>

这是对代码的摆弄

如果你尝试这样做,你会发现对我来说是一些非常奇怪的行为。对于每次调用,Knockout 似乎都在从头开始重新创建整个模板。因此,在第一个"添加"中,添加一个元素。在第二个添加时,再次添加第一个和第二个,依此类推。

无论我尝试什么,我都无法使它工作,但是这个使用afterRender的版本有效:

<ul data-bind="foreach: { data: contents, 
                          afterRender: function(e) { e[1].scrollIntoView(false); } }">
    <li data-bind="text: field"></li>
</ul>

不同之处在于,我不是直接获取元素,而是获取所有 DOM 元素的数组。

您也可以在小提琴中测试行为。如果您继续添加项目,当屏幕到达底部时,它将开始滚动到新添加的元素。

为什么我不能为此使用afterAdd?疯狂的行为到底发生了什么?

似乎afterAdd对于实际呈现的每个元素都调用一次。 在您的示例中,每次添加项目时都会调用 3 次。 第一次(对我来说,至少在 Chrome 中(是使用文本节点,它没有scrollIntoView方法。 最简单的解决方案是在调用该方法之前进行检查,尽管这对我来说仍然是一种捏造:

<ul data-bind="foreach: { data: contents, afterAdd: function(e) { if (e.scrollIntoView) e.scrollIntoView(false); } }">
    <!-- ... --->
</ul>

这样,它只会尝试滚动具有可用方法的元素。

更新的小提琴