【问题标题】:KnockoutJS: show HTML - fill HTMLKnockoutJS:显示 HTML - 填充 HTML
【发布时间】:2019-02-20 19:14:20
【问题描述】:

我需要用 KnockoutJS 实现一个有趣的效果。假设我有一个最简单的模型:

var Item = function () {
    var self = this;
    self.title = ko.observable("");
};

当然我有一个 ViewModel:

var ItemList = function () {
var self = this;
self.list = ko.observableArray();
}
然后乐趣就开始了。在 ViewModel 中,我得到了一些 HTML 标记块。多少——未知。对于每个块,我需要立即显示 HTML 标记:

var blocks = await getBlocks();
$.each(blocks, function (index, value) {
    //At this point (as planned), the blocks should be displayed 
    //together with a rotating loading animation.
    self.list.push(new Item());
});

接下来(再次在 ViewModel 中)我需要获取数据来填充这些块:

$.each(self.list(), async function (index, value) {
    var data = await getData("some-url");
    //At this point, the blocks should be filled with data, 
    //and the spinning loading animation should disappear.
    self.list().push(data.results[0].title);
});
现在一起:

 var Item = function () {
    var self = this;
    self.title = ko.observable("");
};

var ItemList = function () {
    var self = this;
    self.list = ko.observableArray();
    var blocks = await getBlocks();
    $.each(blocks, function (index, value) {
        self.list.push(new Item());
    });

    $.each(self.list(), async function (index, value) {
        var data = await getData("some-url");
        self.list().push(data.results[0].title);
    });
};

ko.applyBindings(new ItemList());
所有这些丑陋的 HTML 看起来非常简单:

<div data-bind="foreach: list">
    <span data-bind="text: title"></span>
</div>
这种方法不能按预期工作。而且我不明白你怎么能用 KnockoutJS 做到这一点。这甚至可能吗?

【问题讨论】:

    标签: javascript ajax knockout.js


    【解决方案1】:

    你的这行代码显然是错误的:

    self.list().push(data.results[0].title);
    

    应该是:

    value.title(data.results[0].title);
    

    【讨论】:

    • 是的,这确实是一个错误。但是你对这个问题的解决方案有什么看法。
    • 我不知道您的期望是什么以及它的行为方式有何不同。仅仅说它“不起作用”是不够的。
    • 这不是不行,而是我不明白怎么做。我需要在加载文档后似乎是空的 HTML 块。只有在使用 Ajax 加载数据后才会填充它们。
    • 我没有在您的代码中看到任何不合适的地方,但也许我不明白您遇到了什么问题。
    【解决方案2】:

    这是一个假设的示例:

    • 有一个调用告诉我们最终要渲染多少项
    • 对于这些项目中的每一项,都需要完成一个调用来呈现实际的 UI

    我已让各个项目负责自己加载数据。这样可以更轻松地将接收到的数据(可以以任何顺序返回)写入相应的列表项。

    您将看到 UI 渲染的步骤:

    1. 正在加载检索数据以呈现初始列表的调用:显示一般加载消息
    2. 我们为要检索的每个项目创建了一个列表项目。所有项目都已开始加载数据,但在加载完成之前会显示加载状态
    3. 一个接一个,单个数据加载完成,列表元素收到它们的内容。

    const { getProductIdsAsync, getProductAsync } = apiMethods();
    
    function Item(id) {
      this.name = ko.observable(null);
      this.loading = ko.pureComputed(() => !this.name());
      
      getProductAsync(id).then(this.name);
    };
    
    Item.fromId = id => new Item(id);
    
    function List() {
      this.items = ko.observableArray([]);
      this.loading = ko.pureComputed(() => !this.items().length);
      
      getProductIdsAsync()
        .then(ids => ids.map(Item.fromId))
        .then(this.items);
    }
    
    ko.applyBindings({ list: new List() });
    
    
    // Mocking of some async API, not relevant to question:
    function apiMethods() {
      const productCatalogDB = {
        1: "Apples",
        2: "Oranges",
        3: "Bananas"
      };
    
      const delayed = (f, minT, maxT) => 
        (...args) => 
          new Promise(res => {
            setTimeout(
              () => res(f(...args)),
              minT + Math.random() * (maxT - minT)
            )
          });
    
      return {
        getProductIdsAsync: delayed(
          () => Object.keys(productCatalogDB), 500, 1200),
        getProductAsync: delayed(
          id => productCatalogDB[id], 500, 1500)
      };
    }
    .loading {
      opacity: .6;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
    
    <p data-bind="visible: list.loading">
      Loading catalog ids...
    </p>
    
    <ul data-bind="foreach: list.items">
      <li data-bind="css: { loading: loading }, text: name() || 'Loading...'">
        
      </li>
    </ul>

    【讨论】:

    • 请原谅我花了这么长时间来回答。你给出了一个惊人的,详尽的答案。非常感谢。你帮我解决了我的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    • 2017-11-15
    • 2018-03-04
    • 1970-01-01
    • 2019-01-01
    相关资源
    最近更新 更多