是否有任何方法可以跟踪Knockout Observable Array项目在UI中显示?

时间:2016-08-25 06:45:25

标签: javascript knockout.js

我使用foreach with pagination向用户显示通知列表。现在,我想知道是否在屏幕上为用户显示该项目的时间足以将通知状态从“新建”更新为“已查看”。我无法将其更新为所有渲染的项目,因为我使用分页时可能无法显示某些项目,我也希望在显示足够的时间后将其标记为已更新(例如5秒)

1 个答案:

答案 0 :(得分:1)

Knockout有一个非常方便的rateLimit扩展程序,可用于执行延迟更新。通过创建当前页面的可观察计算副本,并将其扩展为仅在停止更改后5秒通知您,您可以将该页面上的项目更新为read状态。例如:

var delayedPage = ko.computed(function() {
  // Loop through the items that are rendered (a computed of `page`)
  // Note: this makes the computed impure
  itemsOnDisplay().forEach(function(item) {
    // Set an observable status property of their viewmodel
    item.read(true);
  });

  // This creates the subscription to page changes
  return page();
}, this).extend({ 
  rateLimit: { 
    timeout: 5000, 
    method: "notifyWhenChangesStop" 
  }
});

在一个工作示例中:

  • 具有布尔read可观察
  • 的项目集合
  • 一个可观察的page媒体资源,告诉我们我们在哪个页面
  • 一组itemsOnDisplay的计算集,用于保存当前呈现的项目
  • 在最后一页更改后5秒更新的当前页面的速率限制反映



var ViewModel = function(data) {
  this.itemsPerPage = 6;
  this.page = ko.observable();
  this.items = ko.observableArray(data); 
    
 
  this.displayItems = ko.pureComputed(function() {
    var start = this.page() * this.itemsPerPage;
    var end = start + this.itemsPerPage;
    return this.items().slice(start, end);
  }, this);
  
  this.canGoBack = ko.pureComputed(function() {
    return this.page() > 0;
  }, this);
  
  this.canGoForward = ko.pureComputed(function() {
    return (this.page() + 1) * this.itemsPerPage < this.items().length;
  }, this);
  
  // The important part:
  this.delayedPage = ko.computed(function() {
    var currentPage = this.page();
    if (typeof currentPage === "undefined") return null;
    
    this.displayItems().forEach(function(item) {
      item.read(true);
    });
    
    console.log("Read items on page " + currentPage);
    return currentPage;
  }, this).extend({ rateLimit: { timeout: 5000, method: "notifyWhenChangesStop" } });
    
  this.page(0);
  
}

ViewModel.prototype.prev = function() {
  this.page(Math.max(this.page() - 1, 0));
};

            
ViewModel.prototype.next = function() {
  this.page(Math.min(this.page() + 1, Math.ceil(this.items().length / this.itemsPerPage)));
};

            
            
            
var myData = [];
for (var i = 0; i < 50; i += 1) {
  myData.push({
    label: "Item " + i,
    read: ko.observable(false)
  });
}

var vm = new ViewModel(myData);

ko.applyBindings(vm);
&#13;
li::after {
  content: "new";
  font-style: italic;
  margin-left: 1rem;
  padding: .25rem;
  background: orange;
}

.is-read {
  background: #efefef;
}

.is-read::after {
  display: none;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: displayItems">
  <li data-bind="text: label, css: {'is-read': read }"></li>
</ul>

<button data-bind="click: prev, enable: canGoBack">prev</button>
<button data-bind="click: next, enable: canGoForward">next</button>
&#13;
&#13;
&#13;