延迟加载到 ui-router 中的多个视图

Lazyload to multiple views in ui-router

几个月前我创建了主题:,我在其中询问了如何在同一页面中呈现多个视图。我的 objective 创建了一个作为桌面应用程序的 Web 应用程序,具有最小化、最大化、关闭和类似功能的视图。

好吧,我的应用程序已准备就绪,但我遇到了一个问题,当我将我的应用程序投入生产时,一些计算机需要很长时间才能呈现所有视图。在下图中,我们可以看到服务器对 return 我的模板 URL 的很多请求。

有办法避免这种情况吗?我一直在寻找 templateURL 的延迟加载,但我没有找到。 :(

This plunkr was the approach what I used。我的所有视图只有一个状态(我当前的 app.config 有 103 个视图):

routerApp.config(function($stateProvider) {

  $stateProvider.state('mainState', {
    views: {
      'CompanyView': {
        templateUrl: 'Company.html'
      },
      'PeopleView': {
        templateUrl: 'People.html'
      },
     .....
     ....
    }
  })


});

简介

您处理解决方案的方式是您面临问题的原因,因为您对单个状态的视图太多,最终将不得不加载所有视图以设置该状态,因此每次访问状态时,ui-router 都必须加载每个模板才能设置视图。对于少量模板可能不会造成问题,但是对于像您这样的大量模板,这绝对是一个问题。

Ng 模板

您可以尝试使用 <script type="text/ng-template"... 在您的页面中缓存您的模板,以防止加载时间,顺便说一句,这是一个很好的做法。通常它是生产构建优化的一部分,加载模板缓存中的所有模板,这样应用程序加载时间就会显着减少,前提是您不必等待 http 调用来加载页面。它确实会提高你的情况的性能,但我没有一个基准来确保它是否足以满足你的情况。

基于组件的解决方案

无论如何,您始终可以实现界面组件以按照您想要的方式运行,并以无需加载一百个模板来为用户显示单个面板的方式进行优化。

我的建议是,不要使用 ui-router,而是使用基于组件的解决方案,创建一个指令组件来保存每个 window 的面板内容及其行为;并使用控制器来管理打开和关闭面板的状态,保存和管理列表中每个打开的面板等。例如:

<nav>
  <button ng-click="openPanel({title: 'My Panel Title', templateUrl: 'myPanel.html'>">
    Open myPanel
  </button>
<nav>
<main>
  <panel ng-repeat="panel in openedPanels"></panel>
</main>

下面的代码片段使用 bootstrap 4 css 实现了这种方法,每个面板都是一个 bootstrap 卡片,并且它有一个面板列表可以打开,点击一个导航列表它将相应的面板添加到打开的面板列表中,其中 angularjs 可以使用 ng-repeat 在 html 上呈现它。这样,只会渲染打开的window,因此,只会加载打开的window模板。

Disclaimer: This is a very simple example implemented not using the best practices available out there. If you intend to use this approach you should implement it based on your application to fit better the needs of your architecture, this one is not a complete functional component, it's just an example for the sake of the demonstration.

angular.module('app', [])
  .controller('PanelsCtrl', function($scope) {
  
    // available windows to be opened
    $scope.panels = [
      { title: 'Window 1', templateUrl: 'window1.html' },
      { title: 'Window 2', templateUrl: 'window2.html' }];
    
    // all currently opened panels
    $scope.openedPanels = [];
    
    // opens a panel (a.k.a, adds a panel
    //  to the opened panels list)
    $scope.openPanel = function(panel) {
      if ($scope.openedPanels.indexOf(panel) === -1)
        $scope.openedPanels.push(panel);
    };
    
    // close a panel (a.k.a, removes a panel
    //  from the opened panels list)
    $scope.onClosePanel = function(panel) {
      $scope.openedPanels.splice($scope.openedPanels.indexOf(panel), 1);
    };
  })
  .directive('window', function($templateRequest, $templateCache, $compile) {
    return {
      restrict: 'E',
      scope: {
        panel: '=',
        onClosePanel: '&'
      },
      template: `
        <div class="card">
          <h4 class="card-header">
            <span>{{ panel.title }}</span>
            <button
              ng-click="onClosePanel(panel)"
              type="button"
              class="close"
              data-dismiss="modal"
              aria-label="Close">
              <span aria-hidden="true">&times;</span>
            </button>
          </h4>
          <div class="card-body">
           <ng-include src="panel.templateUrl"></ng-include>
          </div>
        </div>
      `
    }
  })
  // example controlelr to be used with ng-controller
  .controller('Window1Ctrl', function($scope) {
    $scope.window1Prop = 'This is a property from Window1Ctrl'
  })
@import 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css'
<div ng-app="app">
  <div class="container" ng-controller="PanelsCtrl">
    <div class="row">
      <div class="col-sm-3">
        <ul class="nav flex-column">
          <li class="nav-item" ng-repeat="panel in panels">
            <a class="nav-link active" href="#" ng-click="openPanel(panel)">
            {{ panel.title }}
          </a>
          </li>
        </ul>
      </div>
      <div class="col-sm-9">
        <window ng-repeat="panel in openedPanels" panel="panel" on-close-panel="onClosePanel(panel)">
        </window>
      </div>
    </div>
  </div>
  
  <!-- NG-TEMPLATES -->
  
  <script type="text/ng-template" id="window1.html">
    <div ng-controller="Window1Ctrl">
      <b>{{panel.title}}</b>
      <h5>window1Prop: {{ window1Prop }}</p>
    </div>
  </script>
  <script type="text/ng-template" id="window2.html">
    <em>{{panel.title}}</em>
  </script>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.js"></script>