【问题标题】:Delaying Knockout's visible binding?延迟 Knockout 的可见绑定?
【发布时间】:2014-08-21 16:31:36
【问题描述】:

我有一个购物车。当它为空时,我想显示一个带有“空”消息的 div。当其中有项目时,我想显示一个包含项目的 div。目前,我有这样的东西......

<div style="display: none" data-bind="visible: items().length == 0">Empty</div>
<div style="display: none" data-bind="visible: items().length > 0">Not Empty</div>

...还有这个...

function ViewModel() {
    var self = this;

    self.items = ko.observableArray([]);
};

现在,我正在使用 AJAX 加载商品,这意味着对于购物车中是否有商品存在一个初始阶段的不确定性。这意味着页面从显示“空”div 开始,然后很快,在看到有项目后,将其替换为“非空”div——这个过程在屏幕上看起来很笨重。

如何在我的 AJAX 完成并且我知道项目数之前暂停 div 上的 visible 函数?

我想到的一件事(看到工作here)是创建一个单独的属性showEmpty...

<div style="display: none" data-bind="visible: showEmpty">Empty</div>
<div style="display: none" data-bind="visible: items().length > 0">Not Empty</div>

...并默认将其设置为undefined。这意味着 visible 在定义 showEmpty 之前不会解析。然后我在 AJAX 调用中定义它...

self.items = ko.observableArray([]);
self.showEmpty = ko.observable(undefined);

// Fake AJAX
setTimeout(function() {
    self.items([1]);        
    self.showEmpty(self.items().length == 0);
}, 2000);

这 100% 有效,但它提出了一个新问题:我现在 手动 更新一个 observable。如下所示,当我想在数组中添加或删除项目时,这些函数现在必须担心更新showEmpty 属性。

self.addItem = function() {
    self.items.push(1);
    self.showEmpty(false);
};

self.removeItem = function() {
    self.items.pop();
    self.showEmpty(self.items().length == 0);
};

我觉得 KO 的全部目的是避免这种事情。那么,我想要的是某种方法来设置 only 对 div 的 visible 函数的分辨率的初始延迟。在最初的等待之后,我希望 visible 函数根据可观察数​​组的 .length 进行更新。

谢谢!

【问题讨论】:

  • 您可以编写自己的绑定或使用动画类。
  • 或者只使用第二个名为 Loading 的变量,将其设置为 true,然后将 ajax 的末尾设置为 false。然后只需将该变量包含在任何一方的显示要求中即可。

标签: javascript knockout.js


【解决方案1】:

@pquest 在评论中为我提供了解决方案,因此我将其详细放在此处以供其他人稍后查看。

从我更新的fiddle 中可以看出,我添加了一个loadingDone 可观察对象,并在visible 绑定中包含了对它的引用...

<div style="display: none" data-bind="visible: items().length == 0 && loadingDone">Empty</div>
<div style="display: none" data-bind="visible: items().length > 0">Not Empty</div>

在我的脚本中,我能够删除所有手动更新...

function ViewModel() {
    var self = this;    

    self.items = ko.observableArray([]);
    self.loadingDone = ko.observable(false);

    // Fake AJAX
    setTimeout(function() {
        self.items([1]);        
        self.loadingDone(true);
    }, 2000);

    self.addItem = function() {
        self.items.push(1);
    };

    self.removeItem = function() {
        self.items.pop();
    };
};

不错!我仍然希望我可以在不添加额外的 observable 的情况下完成相同的操作,但这比我拥有的要好得多,所以我很高兴。

【讨论】:

  • 解决此问题的另一种方法:在您完成加载必要数据之前,不要显示页面/购物车/您认为正确的任何内容。这很常见:viewModels 通常有一个 activate 方法(或类似的东西),并且页面将被隐藏直到 activate 方法完成(通常带有异步加载的承诺)。如果您使用这种方法,您可以在您的激活方法中加载购物车数据,并且完全没有问题。由于您会多次遇到此问题,并且引入额外的 observable 是额外的内务管理,因此您可以以通用的方式解决问题。
  • 这是有道理的。我最终在我的项目中做了类似的事情,但没有考虑让它更通用并在其他地方使用它。我一定会回去做这样的事情。谢谢!
【解决方案2】:

(没有足够的代表发表评论,抱歉)除非您绝对必须使用淘汰赛来提高知名度,否则为什么不使用 jQuery 来代替使用 .show() 和 .hide() 函数来处理 AJAX 中的 div .在 AJAX 调用结束时检查可观察的项目长度,如果它大于 0,请检查 .show(),否则它会保持隐藏状态..(除非你需要那里的“空”消息)

【讨论】:

  • 我使用 KO 这样做的原因是因为它允许我简单地陈述我希望 div 可见的条件然后忘记它。使用 jQuery 方法,我必须编写代码来获取 ID,检查它们的值,然后获取其他 ID 并对其运行显示/隐藏等。不过,感谢您的建议。我很感激。 :)
【解决方案3】:

如果您不想添加 observable,可以将 setTimeout 移到 viewModel 之外,然后从那里调用 ViewModel 中的 ajax 函数。

var ViewModel = function() {
    // other code

    self.fake_ajax = function() {
    };
}

var vm = new ViewModel()
ko.applyBindings(vm);

setTimeout(function() {
    vm.fake_ajax();
}, 3000);

这是fiddle

【讨论】:

  • 在你的小提琴中,请注意当你第一次点击 RUN 时它显示“购物车是空的”?这就是我想要避免的,因为当然,在某些情况下它是不正确的,并且会使人们感到困惑。而且,再一次,当事情加载时它看起来很糟糕,然后在一瞬间迅速闪烁。不过还是谢谢。 :)
  • 对不起,我误解了你的要求。
猜你喜欢
  • 1970-01-01
  • 2014-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-07
  • 1970-01-01
  • 1970-01-01
  • 2014-05-24
相关资源
最近更新 更多