4

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

问题。我想创建一个“ScrollIntoView”绑定。由于将元素滚动到视图中需要 DOM 元素,因此我编写了一个自定义绑定,然后我想在我高兴的时候显式地触发它。我从这段代码开始:

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 时,true 值就会一直存在,这导致一些元素滚动到视图中,而用户没有明确地触发它。例如,当我更改视图时,基本上用 if 绑定隐藏了所有元素,然后切换回来,if 绑定将重新触发之前设置为 true 的所有 goToThis 可观察对象。啊!

所以我想出了这个模式并像这样扩展了我的 custum 绑定:

    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 绑定?如果是,您是如何解决的?

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

最好的问候 j

4

3 回答 3

7

您的scrollTo处理程序很好,如下所示:

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

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

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

这样你就不需要重置任何东西,也不需要一个goToThis可观察的每个视图模型。

http://jsfiddle.net/290ew0nr/1/

于 2015-07-06T13:07:52.157 回答
1

scrollintoview在我的淘汰赛应用程序中使用,但从未想过将其放入bindingHandler,可能是因为我不觉得scrollintoview模型和视图之间存在关系。

scrollintoview对我来说,这更像是我们展示数据后的后续行动。

我的做法是用一个css绑定来标记我要标记的item scrollintoview,比如我用css class标记元素current-item,当然最后应该只有一个用这个class标记的item。

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

// 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 提供了一种更好的方法来执行 afterRender 回调http://knockoutjs.com/documentation/template-binding.html#note_4_using_afterrender_afteradd_and_beforeremove

您可以使用template, 并放入scrollintoviewthattemplateafterRender回调。

只是我的2美分。

于 2014-04-10T12:18:09.857 回答
0

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

于 2017-11-19T22:58:43.497 回答