Knockout.js Knockoutjs:ScrollIntoViewTrigger

Knockout.js Knockoutjs:ScrollIntoViewTrigger,knockout.js,triggers,custom-binding,Knockout.js,Triggers,Custom Binding,我最近遇到了一个问题,虽然我为自己解决了这个问题,但我不确定是否还有更好的解决方案,所以我很感谢大家的评论 问题。我想创建一个“ScrollIntoView”绑定。由于将一个元素滚动到视图中需要DOM元素,所以我编写了一个自定义绑定,然后我想随时显式触发它。我从以下代码开始: ko.bindingHandlers.scrollTo = { update: function (element, valueAccessor, allBindings) { var _value

我最近遇到了一个问题,虽然我为自己解决了这个问题,但我不确定是否还有更好的解决方案,所以我很感谢大家的评论

问题。我想创建一个“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">
然后我可以通过调用:

_self.goTohis(true);
到目前为止,一切顺利。然而,我很快就遇到了问题。因为每当我将goTothis()Observable设置为true时,true值就会随之出现,这会导致一些元素滚动到视图中,而用户不会明确地触发它。例如,当我更改视图时,基本上用if绑定隐藏所有元素,然后切换回来,if绑定将重新触发所有goToThis可观测值,之前已设置为true。啊

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

    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);
                }
            }
        }
   };
ko.bindingHandlers.scrollTo = {
    update: function (element, valueAccessor, allBindings) {
        var _value = valueAccessor();
        var _valueUnwrapped = ko.unwrap(_value);
        if (_valueUnwrapped) {
            element.scrollIntoView();
        }
    }
};
<div data-bind="scrollTo: $root.scrolledItem() == $data">
实际上,每次触发时都会重置布尔值

所以我想我的问题是:有人写过scrollIntoView绑定吗?如果是,您是如何解决的

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

致意
j

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

scrollintoview
对我来说更像是我们在视图上呈现数据之后的后续行动

我的方法是使用css绑定来标记我想查看的项目,例如,我用css类标记元素,当然最后应该只有一个项目用这个类标记

然后我需要做的是在重建所有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回调

您可以使用
模板
,并在
模板
后渲染
回调中放置
滚动视图


只要我的2美分。

您的
滚动到
处理程序如下所示:

    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);
                }
            }
        }
   };
ko.bindingHandlers.scrollTo = {
    update: function (element, valueAccessor, allBindings) {
        var _value = valueAccessor();
        var _valueUnwrapped = ko.unwrap(_value);
        if (_valueUnwrapped) {
            element.scrollIntoView();
        }
    }
};
<div data-bind="scrollTo: $root.scrolledItem() == $data">
但是,与其使用一个
goToThis
observable per view模型,不如在根目录中有一个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);
                }
            }
        }
   };
ko.bindingHandlers.scrollTo = {
    update: function (element, valueAccessor, allBindings) {
        var _value = valueAccessor();
        var _valueUnwrapped = ko.unwrap(_value);
        if (_valueUnwrapped) {
            element.scrollIntoView();
        }
    }
};
<div data-bind="scrollTo: $root.scrolledItem() == $data">

这样,您就不需要重置任何内容,也不需要每个视图都有一个可观察的
goToThis
模型


请参见

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

绑定不错!我想我会问UI中的滚动对视图模型意味着什么。我们是在聚焦还是在任意点滚动?例如,滚动到一个特定的像素位置,会有点挫败MVVM抽象的意义!您所实现的当然适合这个特定问题。最接近的现有绑定示例是focus,它在为true时聚焦,在焦点丢失时回写false。我认为这非常符合相同的模式。我经常发现绑定是正确的方式,诀窍是扩大绑定的范围,将问题封装为一个整体,看看旧的解决方案是否仍然适用。如果我要把它分解成一个完整的解决方案,我会考虑像引导导航间谍这样的东西,并提供某种双向绑定,对于特定元素,当项目滚动到时,将绑定属性设置为true,当项目不滚动到时,将其设置为false。我们可以添加在特定元素上触发scroll to的功能,这将反过来将所有其他“ScrolledTo”绑定设置回false。这非常好。它是否可以应用于
选择
的特定
选项