带有角度的动态菜单栏

Dynamic menu bar with angularjs

本文关键字:动态 菜单栏      更新时间:2023-09-26

我正在尝试使用 Angularjs 创建一个菜单栏。我以前用Backbonejs做过类似的事情,但我很难弄清楚如何使用角度来做到这一点。

在我的html文件中,我有以下菜单占位符。

<div id='menu1'></div>
<div id='menu2'></div>
<div id='menu3'></div>
<div id='menu4'></div>
<div id='menu5'></div>

我的许多角度模块在加载时会添加一个菜单(以 run 为单位(。他们每个人都只保留一个特定的插槽(即 menu1..5 (,所以它们不会发生冲突。未加载某些模块时,其菜单不会显示在菜单栏中。

角度模块在概念上看起来像:

angular.module('myModule3', [])
  .service('someService', function($http) {
    // get some data to populate menu (use $http)
    this.menuItems = ['orange', 'apple', 'banana']
  })
  .run(['someService', function(someService) {
    // create a rendered menu item
    ...
    // insert it at id="menu3"
  })

为简单起见,呈现的菜单项应如下所示:

  <ul>
    <li>organge</li>
    <li>apple</li>
    <li>banana</li>
  </ul>

我对角度相当陌生,所以我真的不知道从哪里开始。我一直在阅读directive,但没有看到它们如何适合这里,因为它们需要一些自定义标记(可能是包含 DOM 目标的自定义菜单标签(即 menu..5(。另外,我不清楚如何将其连接到控制器。

更新除了上述base template(在 DOM 中包含任意锚点(和指令(将生成将插入到这些锚点处的 DOM 元素(之外,模板还将促进 DOM 元素的创建。此模板将位于一个单独的文件中,其中包含指令的 DOM 元素将插入到的位置(与指令的常见情况相反,其中已经存在的标记将被替换/插入到与指令定义匹配的特定标记中:

<menu ng-model="Model3DataService" target="#menu3">
  <ul>
    <li ng-repeat="for item in items"></li>
  </ul>
</menu>

同样,来自Backbone/jquery背景是有道理的,但这在angular中可能不是正确的做法。如果是这样,请告诉我如何使基本模板不了解模块和他们放置菜单的位置的假设(即他们分配的菜单栏的哪个插槽(。我很高兴听到其他解决方案...

每个模块都应该定义其菜单加载器:

angular.module('module1', []).
factory('module1.menuLoader', function() {
    return function(callback) {
        callback(['oranges', 'bananas'])
    }
});

应用程序应包含菜单指令,该指令仅当存在时才能加载任何模块的菜单项。

angular.module('app', ['module1']).
directive('menu', ['$injector', function($injector) {
    return {
        restrict: 'A',
        template: 
            '<ul><li ng-repeat="item in items">{{item}}</li></ul>',
        scope: {},
        link: function($scope, $element, $attrs) {
            var menuLoaderName = $attrs.menu+'.menuLoader';
            if ($injector.has(menuLoaderName)) {
                var loaderFn = $injector.get(menuLoaderName);
                loaderFn(function(menuItems) {
                    $scope.items = menuItems;
                });
            }
        }
    };
}]); 

最终的 html:

<div class="content">
    <div menu="module1"></div>
    <div menu="module2"></div>
    <div menu="module3"></div>
</div>

运行应用程序后,将仅加载模块 1 菜单。其他菜单占位符仍为空。

现场演示:http://plnkr.co/edit/4tZQGSkJToGCirQ1cmb6


已更新:如果要在模块端生成标记,最好的方法是将模板放在定义它的模块中的$templateCache,然后将 templateName 传递给应用程序。

angular.module('module1', []).
factory('module1.menuLoader', ['$templateCache', function($templateCache) {
    $templateCache.put('module1Menu', '<ul><li ng-repeat="item in items">{{item}}</li></ul>');
    return function(callback) {
        callback('module1Menu', ['oranges', 'bananas'])
    }
}]);

angular.module('app', ['module1'])
.directive('menu', ['$injector', function($injector) {
    return {
        restrict: 'A',
        template: 
            '<div ng-include="menuTemplate"></div>',
        scope: {},
        link: function($scope, $element, $attrs) {
            var menuLoaderName = $attrs.menu+'.menuLoader';
            if ($injector.has(menuLoaderName)) {
                var loaderFn = $injector.get(menuLoaderName);
                loaderFn(function(menuTemplate, menuItems) {
                    $scope.menuTemplate = menuTemplate;
                    $scope.items = menuItems;
                });
            }
        }
    };
}]);