10

我正在尝试使用 knockoutjs foreach 绑定指定对插入的元素的入口效果。非常简单的设置:

myViewModel.myObservableArray.push({enter:function() { ... });

并在标记中:

foreach:{data:myObservableArray, afterRender:enter}

似乎它应该工作......对吧?但它没有在项目上找到输入功能。我发现确实有效的是:

myViewModel.enter = function(something, item) { item.enter(); };

foreach:{data:myObservableArray, afterRender:$root.enter}

将 enter 函数添加到根视图模型并绑定afterRender到 $root.enter。然后 Enter 将项目作为其第二个参数传递,因此可以反过来调用项目的 enter 函数,但感觉就像一个 hack。

谁能解释这里发生了什么?

谢谢。

编辑:

为了澄清我已经创建了一个fiddle

这样做非常简单,在动画过渡示例中有更深入的介绍。它在根视图模型中为使用 foreach 绑定插入的每个 dom 元素运行一个函数。

所以问题是:如果我想要特定于项目的 afterRender、afterAdd 或 beforeRemove 函数怎么办?我可以看到这很有用。特别是如果使用模板绑定来动态选择模板(注 4)。有没有一种干净的方法可以做到这一点?现在我enter在视图模型的根目录中有一个函数,它只是调用enter项目上的函数,但就像我上面所说的那样,这感觉就像一个 hack。

4

3 回答 3

5

不,这就是它的设计方式。

来自文档

注3:使用“afterRender”、“afterAdd”和“beforeRemove”</p>

有时您可能希望对模板生成的 DOM 元素运行自定义后处理逻辑。例如,如果您使用 jQuery UI 之类的 JavaScript 小部件库,您可能希望截取模板的输出,以便可以在其上运行 jQuery UI 命令将一些呈现的元素转换为日期选择器、滑块或还要别的吗。

通常,对 DOM 元素执行此类后处理的最佳方法是编写自定义绑定,但如果您真的只想访问模板发出的原始 DOM 元素,则可以使用 afterRender。

传递函数引用(函数字面量,或在视图模型上给出函数的名称),Knockout 将在渲染或重新渲染模板后立即调用它。

(强调我的)


正如它所说,自定义绑定是另一种实现方式,并且可能会更好,具体取决于该enter()函数的作用。

于 2012-07-31T21:41:40.473 回答
5

在这种情况下,下划线去抖(_.debounce)是一个很好的解决方案。

模板

data-bind=" template: {foreach:myObservableArray, afterRender: runWhenAllRenderDone }

如果在最后 100 毫秒内未触发 afterRender,则将执行 debounce 函数。

var runWhenAllRenderDone = _.debounce(myFunction, 100);

function myFunction(){
    //do some task but do it for once only
}

是不是很棒?

于 2013-01-17T21:56:22.780 回答
0

找到了另一种没有的解决方法timeout,这种技术是基于虚拟元素的<!-- ko if: $parent.afterRender($index()) --><!-- /ko -->

function ReservationsViewModel() {
    // Editable data
    this.seats = ko.observableArray([
        { name: "Steve", meal: "Standard (sandwich)", price: 343},
        { name: "Steve", meal: "Premium (lobster)", price: 10},
        { name: "Steve", meal: "Ultimate (whole zebra)", price: 290}
    ]);

    this.afterRender = (i) => {
       // checking element rendered is last
       if (i === this.seats().length - 1) { 
           console.log('rendered');
           // our after rendered logic goes here...
       }
    };
}

它的模板是

<tbody data-bind="foreach: seats">
    <tr>
        <td data-bind="text: name"></td>
        <td data-bind="text: meal"></td>
        <td data-bind="text: price"></td>
    </tr>    
    <!-- ko if: $parent.afterRender($index()) --><!-- /ko -->
</tbody>

这个额外的逻辑i === this.seats().length - 1,将检查最后一行是否被渲染。然后我们可以在里面执行我们的 afterRender 逻辑。

于 2019-04-24T07:40:36.350 回答