如何避免每次在KnockoutJS中重绘整个标签?

时间:2017-05-19 21:20:16

标签: performance knockout.js twitter-bootstrap-3 redraw

在这个使用Bootstrap Tabs的基本示例中,每次单击选项卡时,KnockoutJS都会重绘整个选项卡,有没有办法“保存”选项卡的状态,以便下次单击Messages时,KO不会我必须重绘整个事情吗?

绘制需要约100毫秒。 (根据Chromium剖析器),fps下降到1fps。它使整个事情变得非常反应迟钝。

<div>
  <ul class="nav nav-tabs" role="tablist">
    <li role="presentation"><a href="#profile" aria-controls="profile" role="tab" data-toggle="tab">Profile</a></li>
    <li role="presentation"><a href="#messages" aria-controls="messages" role="tab" data-toggle="tab">Messages</a></li>
  </ul>

  <div class="tab-content">
    <div role="tabpanel" class="tab-pane active" id="tab_storage" data-bind="with: BuildingsVM">

    <h2 data-bind="i18next: 'AllOurStorage'"></h2>
    <div class="row" data-bind="foreach: buildingsByType['RawStorage']">
      <div data-bind="template: { name: 'tpl_building' }"></div>
    </div>
    <div class="row" data-bind="foreach: buildingsByType['RefinedStorage']">
      <div data-bind="template: { name: 'tpl_building' }"></div>
    </div>

  </div>
    <div role="tabpanel" class="tab-pane" id="messages" data-bind="messages">
      <div data-bind="foreach: message">
        <span data-bind="text: title"></span>
      </div>
    </div>
  </div>
</div>

是否可以保持DOM的状态,以便每次点击它时KO都不必重绘整个标签? (或另一种解决方案)

当我使用array.push(a_lot_of_things)时,我正在使用以下ko选项来避免不必要的更新:

ko.options.deferUpdates = true;
ko.options.rateLimit = 25;

编辑: 使用Bootstrap JS库切换选项卡。

 $("#MenuTab").on('click','a', function(e) {
   e.preventDefault();
   var id = $(this).attr('href');
   $(this).tab("show");
 });

建筑物'卡'的模板:

<script type="text/html" id="tpl_building">
  <div class="col-xs-10 col-sm-6 col-md-3">
    <div class="card card-raised">
      <div class="card-header"><h3 data-bind="text: buildingName"></h3> </div>
      <div class="card-content">

        <div class="row" data-bind="if: (buildingType == 'RawStorage' || buildingType == 'RefinedStorage')">
          <div class="col-xs-4">
            Usage: <span data-bind="text: getOccupyingSpace"></span> / <span data-bind="text: TotalCapacity"></span>
          </div>
          <div class="col-xs-8">
            <span data-bind="meter: {value: getOccupyingSpace, max: TotalCapacity}"></span>
          </div>
        </div>



        <div class="row">
        <!-- ko foreach: Ressources -->
        <div class="col-md-6" data-bind="if: $parent.TotalCapacity">
          <span data-bind="text: Name"></span> <span data-bind="text: Qte"></span> (<span class="small" data-bind="text: getOccupyingSpace"></span>)
          <!-- ko if: ProductionRate() -->
          <span data-bind="text: ProductionRate()"></span>/s
          <!-- /ko -->
        </div>
        <div class="col-md-6" data-bind="if: ProductionRate">
          <span data-bind="text: Name"></span> <span data-bind="text: getProductionRatePerSecond()"></span>/s (1 every <span data-bind="text: ProductionRate()/1000"></span> sec)
        </div>
        <!-- /ko -->
        </div>


      </div>
      <div class="card-footer">
        <!-- ko if: initialConstructionGoing -->
        <i class="fa fa-exclamation-triangle icon-gradient-warning" class="ko-popover"
  data-bind="popover: initialConstructionGoing, popoverOptions: { title: i18nextko.t('UnderConstruction_potitle') }" ></i>
  <span data-bind="i18next: 'UnderConstruction'"></span> <span data-bind="text: getBuildProgress"></span>
  <span data-bind="meter: {p: getBuildProgress, onComplete: 'remove'}"></span>
  <span data-bind="WorkersAssigned().length"></span>/<span data-bind="WorkersBuild"></span>
        <!-- /ko -->

      </div>
    </div>
  </div>
</script>

“米”的自定义绑定(进度条):

  ko.bindingHandlers.meter = {
      init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
          // This will be called when the binding is first applied to an element
          // Set up any initial state, event handlers, etc. here
          var progress = ko.unwrap(valueAccessor());

          if(progress.value) {
            var value = ko.unwrap(progress.value);
            var max = ko.unwrap(progress.max);

            if(value === 0 && max === 0) {
              var percentage = 0;
            } else {
              var percentage = (value/max)*100;
            }
          } else {
            var percentage = ko.unwrap(progress.p);
          }




          $progress_tpl = $('<div class="meter"><span style="width: '+percentage+'%"></span></div>');
          if(progress.onComplete) {
            $progress_tpl.attr('data-oncomplete', progress.onComplete);
          }
          $(element).append($progress_tpl);


      },
      update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
          // This will be called once when the binding is first applied to an element,
          // and again whenever any observables/computeds that are accessed change
          // Update the DOM element based on the supplied values here.
          var progress = ko.unwrap(valueAccessor());
          if(progress.value) {
            var value = ko.unwrap(progress.value);
            var max = ko.unwrap(progress.max);
            var percentage = (value/max)*100;

          } else {
            var percentage = ko.unwrap(progress.p);

          }

          $(element).find('.meter span').stop().animate({'width': percentage+'%'}, (bindingContext.$root.cf.refreshEvery), 'swing', function() {
            if(percentage >= 100) {
              if($(element).find(".meter").attr('data-oncomplete') == 'remove') {
                $(element).hide(300, function() {
                  $(element).remove();
                  ko.cleanNode(element);

                });
              } else if($(element).find(".meter").attr('data-oncomplete') == 'reset') {
                $(element).hide(300, function() {
                  $(element).remove();
                });
              } else {

              }

            }
          });


      }
  };

我的KO主VM:

var mainVM = {
    Ressources: new RessourcesVM(),
    Buildings: new BuildingsVM(),
    cf: {
      ...
    }
}

还修改了原始标签内容代码以反映真实代码(使用模板)。

我会做一个JSfiddle,但由于一些不明确的原因,它似乎无法正常工作(新的路由器固件可能是问题,阻止CDN)à

为了更好地理解cotext,您可以查看我的另一个问题:How can I optimize my KnockoutJS pureComputed function?

查看控制台中的DOM树,即使选项卡未处于活动状态,所有元素仍然存在 - 可能还有其他因素造成延迟。

0 个答案:

没有答案