Knockoutjs:ScrollIntoViewTrigger

时间:2013-12-23 09:06:21

标签: knockout.js triggers custom-binding

我最近遇到了一个问题,虽然我为我解决了这个问题,但我不确定那里是否有更好的解决方案,所以我很感激任何意见。

问题。我想创建一个'ScrollIntoView'绑定。由于将一个元素滚动到视图中,需要DOM-Element,我编写了一个自定义绑定,然后我想明确地触发它,只要我满意。我从这段代码开始:

ko.bindingHandlers.scrollTo = {
    update: function (element, valueAccessor, allBindings) {
        var _value = valueAccessor();
        var _valueUnwrapped = ko.unwrap(_value);
        if (_valueUnwrapped) {
            element.scrollIntoView();
        }
    }

};

绑定:

<div data-bind="scrollTo: goToThis">

在ViewModel中我有这个可观察的内容:

_self.goToThis = ko.observable(false).extend({notify: 'always'});

然后我可以通过调用来触发:

_self.goTohis(true);

到目前为止,这么好。但是我很快遇到了问题。因为每当我将goTothis()Observable设置为true时,真正的值就会停留在它上面,导致一些元素滚动到视图中,而用户没有明确地触发它。例如,当我更改视图时,基本上用if绑定隐藏所有元素,然后切换回来,if绑定将重新触发之前已设置为true的所有goToThis observable。啊!

所以我想到了这种模式,并扩展了我的密码绑定:

    ko.bindingHandlers.scrollTo = {
        update: function (element, valueAccessor, allBindings) {
            var _value = valueAccessor();
            var _valueUnwrapped = ko.unwrap(_value);
            if (_valueUnwrapped) {
                element.scrollIntoView();
// resets the trigger value to false. Otherwise there will be more and more ViewModels, where the value is true.
                if (ko.isWriteableObservable(_value) && typeof (_valueUnwrapped) === 'boolean') {
                    _value(false);
                }
            }
        }
   };

每次触发时基本上重置布尔值。

所以我想我的问题是这样的:有没有人写过scrollIntoView绑定?如果是的话,你是怎么解决的?

通常,是否存在编写触发器的模式?即我只是想触发一个绑定,但没有真正的价值变化。

最好的问候 Ĵ

3 个答案:

答案 0 :(得分:6)

你的scrollTo处理程序就像这样:

ko.bindingHandlers.scrollTo = {
    update: function (element, valueAccessor, allBindings) {
        var _value = valueAccessor();
        var _valueUnwrapped = ko.unwrap(_value);
        if (_valueUnwrapped) {
            element.scrollIntoView();
        }
    }
};

但是不是使用每个视图模型的goToThis可观察对象,更好的是在你的根中有1个observable,它跟踪当前的滚动项,然后在你的绑定中传递一个表达式,如下所示:

<div data-bind="scrollTo: $root.scrolledItem() == $data">

这样您就不需要重置任何内容,并且您不需要每个视图模型goToThis可观察。

请参阅http://jsfiddle.net/290ew0nr/1/

答案 1 :(得分:1)

我在我的淘汰应用中使用scrollintoview,但从未考虑过将其放入bindingHandler,可能是因为我觉得scrollintoview是模型与模型之间的关系观点。

在我们提供有关视图的数据后,对我的{p> scrollintoview更像是一个跟进行动。

我的方法是使用css绑定来标记我想要的项目scrollintoview,例如,我用css类current-item标记元素,当然应该只有一个项目标记最后这个班。

然后我需要做的是在重建所有DOM之后将其滚动到视图中。 为了在我运行scrollintoview之前允许ko构建视图,我需要延迟操作。

// do my model logic above
// then fire my after-render callback
setTimeout(function() {
  $('.current-item').scrollintoview({direction: 'y'});
  // I am using a different scrollintoview library: https://github.com/litera/jquery-scrollintoview
}, 0);

顺便说一句,ko提供了一种更好的方式来做后续回调http://knockoutjs.com/documentation/template-binding.html#note_4_using_afterrender_afteradd_and_beforeremove

您可以使用template,并将scrollintoview放入template的{​​{1}}回调中。

只需2美分。

答案 2 :(得分:0)

解决此问题的另一种方法是使用自定义事件。当您需要进行滚动(提供任何相关数据)时,您可以从ViewModel触发事件,然后在页面上定义一个处理程序以响应该事件。这样,您就可以在事件处理程序中执行所有DOM操作,并使ViewModel与HTML无关。