1. 程式人生 > >AngularJS+Bootstrap3多級導航選單

AngularJS+Bootstrap3多級導航選單

AngularJS體驗式程式設計系列文章,將介紹如何用angularjs構建一個強大的web前端系統。angularjs是由Google團隊開發的一款非常優秀web前端框架。在當前如此多的web框架下,angularjs能脫穎而出,從架構設計上就高人一等,雙向資料繫結,依賴注入,指令,MVC,模板。Angular.js創新地把後臺技術融入前端開發,掃去jQuery一度的光芒。用angularjs就像寫後臺程式碼,更規範,更結構化,更可控。

關於作者

  • 張丹(Conan), 程式設計師Java,R,PHP,Javascript
  • weibo:@Conan_Z
  • email: [email protected]

bootstrap3-navbar

前言

在上一篇文章中Angular結合Bootstrap3的導航選單,我們看到直接用Bootstrap3的預設導航菜單隻支援到二級的選單,如果想做成多級導航選單,那又要自己動手了。

本文將介紹如何實現多限級導航選單。

目錄

  1. 靜態多級選單實現
  2. 動態多級選單實現

1. 靜態多級選單實現

要實現多級選單,我們要分兩步走,第一步就是把靜態選單的功能實現,通過純靜態的HTML程式碼完成。第二步,通過Angluarjs進行動態實現,最後把資料和程式分離,通過Ajax載入多級選單資料。

我們先從靜態多級選單開始動手,一個六級導航選單是什麼樣子呢?

m-nav1

如上圖所示,我們定義一些功能需求。

  • 1級選單是導航條上的文字。
  • 當1級選單導航事件被觸發,顯示2級選單導航,在1級選單的正下方顯示。
  • 當2級選單導航事件被觸發,顯示3級選單導航,在2級選單的右方顯示。
  • 當3級選單導航事件被觸發,顯示4級選單導航,在3級選單的右方顯示。
  • 以此類推,不考慮下級選單顯示出界問題。

繼續上文中的專案環境,增加一個新HTML檔案: page3.html


~ vi D:\workspace\javascript\angular-navbar\page3.html

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <title>多級導航選單</title>
    <meta name="description" content="多級導航選單">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="fragment" content="!" />

    <link rel="stylesheet" href="/bower_components/bootstrap/dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="/css/main.css">
</head>
<body ng-app="page2">

<div class="container">
    <div class="row" ng-controller="NavbarCtrl">
        <nav class="navbar navbar-default" role="navigation">
            <div class="navbar-header">
                <a class="navbar-brand" href="#">多級選單導航</a>
            </div>

            <div class="collapse navbar-collapse navbar-ex1-collapse">
                <ul class="nav navbar-nav">
                    <li class="active"><a href="#">Link</a></li>
                    <li><a href="#">Link</a></li>
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">Multi Level <b class="caret"></b></a>
                        <ul class="dropdown-menu menu-top">
                            <li><a href="#">Level 1</a></li>
                            <li class="dropdown-submenu"> <a tabindex="-1" href="#">More options</a>
                                <ul class="dropdown-menu">
                                    <li><a tabindex="-1" href="#">Level 2</a>
                                    </li>
                                    <li class="dropdown-submenu"> <a href="#">More..</a>
                                        <ul class="dropdown-menu">
                                            <li><a href="#">Level 3</a>
                                            </li>
                                            <li><a href="#">Level 3</a>
                                            </li>
                                            <li class="dropdown-submenu"> <a href="#">More..</a>
                                                <ul class="dropdown-menu">
                                                    <li><a href="#">Level 4</a>
                                                    </li>
                                                    <li><a href="#">Level 4</a>
                                                    </li>
                                                    <li class="dropdown-submenu"> <a href="#">More..</a>
                                                        <ul class="dropdown-menu">
                                                            <li><a href="#">Level 5</a>
                                                            </li>
                                                            <li><a href="#">Level 5</a>
                                                            </li>
                                                        </ul>
                                                    </li>

                                                </ul>
                                            </li>

                                        </ul>
                                    </li>
                                    <li><a href="#">Level 2</a>
                                    </li>
                                    <li><a href="#">Level 2</a>
                                    </li>
                                </ul>
                            </li>
                            <li><a href="#">Level 1</a></li>
                        </ul>
                    </li>
                </ul>
            </div>
        </nav>
    </div>
</div>

<script src="/bower_components/jquery/dist/jquery.min.js"></script>
<script src="/bower_components/angular/angular.min.js"></script>
<script src="/bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="/bower_components/angular-route/angular-route.min.js"></script>
<script src="/bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>

<script src="/js/app.js"></script>

</body>
</html>

新建一個css檔案:main.css


~ vi D:\workspace\javascript\angular-navbar\css\main.css

.dropdown:hover .menu-top {
    display: block;
}

.dropdown-submenu{
    position:relative;
}

.dropdown-submenu > .dropdown-menu{
    top:0;
    left:100%;
    margin-top:-6px;
    margin-left:-1px;
    -webkit-border-radius:0 6px 6px 6px;
    -moz-border-radius:0 6px 6px 6px;
    border-radius:0 6px 6px 6px;
}

.dropdown-submenu:hover > .dropdown-menu{
    display:block;
}

.dropdown-submenu > a:after{
    display:block;
    content:" ";
    float:right;
    width:0;
    height:0;
    border-color:transparent;
    border-style:solid;
    border-width:5px 0 5px 5px;
    border-left-color:#cccccc;
    margin-top:5px;
    margin-right:-10px;
}

.dropdown-submenu:hover > a:after{
    border-left-color:#ffffff;
}

.dropdown-submenu .pull-left{
    float:none;
}

.dropdown-submenu.pull-left > .dropdown-menu{
    left:-100%;
    margin-left:10px;
    -webkit-border-radius:6px 0 6px 6px;
    -moz-border-radius:6px 0 6px 6px;
    border-radius:6px 0 6px 6px;
}

通過HTML和CSS就實現了多級選單的靜態展示效果,如果導航選單不是經常變化,那麼用靜態的方式,把程式碼寫死就可以了。但有一些場景,選單是需要動態生成,比如通過許可權控制訪問連結,每個使用者的許可權不一樣,那麼能看到的選單選項也就不一樣,這個時候就需要做成動態的,用程式去控制選單的載入和展示。

2. 動態多級選單實現

有了靜態多級導航選單的HTML程式碼結構,改寫成動態的,其實也不太複雜。

我們需要做2件事:

  • 把導航選單的資料結構化儲存,比如 存放到檔案 nav.json。
  • 用Angularjs的API載入nav.json資料,進行展示。

我們先定義一下導航選單的資料格式,以JSON格式定義,每個選單項都有3個屬性欄位

  • label: 導航選單項顯示的名字。
  • link: 導航選單項的跳轉連結,可以不定義。
  • children: 導航選單項的子選單,迴圈物件儲存。

{
    "label": "levelA",
    "link": "#",
    "children": [
        {
            "label": "levelB",
            "link": "#",
            "children": []
        }
    ]
}

下面我們用真實的資料定義導航選單,以我的金融系統為例。

m-nav3

新建JSON資料檔案:nav.json。


~ vi D:\workspace\javascript\angular-navbar\js\nav.json

[
    {
        "label": "債券",
        "children": [
            {
                "label": "可轉債",
                "children": [
                    {"label": "可轉債溢價率分析","link":"#"},
                    {"label": "可轉債NS定價","link":"#"},
                    {"label": "可轉債歸因分析","link":"#"},
                    {"label": "可轉債套利實時監控","link":"#"}
                ]
            },
            {
                "label": "信用債",
                "children": [
                    {"label": "交易所債券監控","link":"#"}
                ]
            },
            {
                "label": "利率債","link":"#",
                "children": []
            },
            {
                "label": "國債期貨",
                "children": [
                    {"label": "國債期貨表現分析","link":"#"},
                    {"label": "國債期貨實時套利監控","link":"#"},
                    {"label": "IRR歷史時間序列查詢","link":"#"},
                    {"label": "IRR實時監控","link":"#"}
                ]
            }
        ]
    },
    {
        "label": "股票",
        "children": [
            {
                "label": "基本面分析",
                "children": [
                    {"label": "上市公司基本面資料檢視","link":"#"}
                ]
            },
            {
                "label": "量化選股策略",
                "children": []
            }
        ]
    },
    {
        "label": "巨集觀",
        "children": [
            {
                "label": "巨集觀資料",
                "children": [
                    {"label": "巨集觀資料概覽","link":"#"}
                ]
            },
            {
                "label": "巨集觀經濟預測",
                "children": []
            },
            {
                "label": "巨集觀經濟和大類資產表現",
                "children": []
            }
        ]
    }
]

我們看到這個導航選單的資料,有3級,“債券–>可轉債–>可轉債歸因分析”,那麼接下我們就直接實現對三級選單的程式設計。建立HTML檔案page4.html。


~ vi D:\workspace\javascript\angular-navbar\page4.html

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <title>多級動態導航選單</title>
    <meta name="description" content="多級動態導航選單">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="fragment" content="!" />

    <link rel="stylesheet" href="/bower_components/bootstrap/dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="/css/main.css">
</head>
<body ng-app="page4">

<div class="container">
    <div class="row" ng-controller="NavbarCtrl">
        <nav class="navbar navbar-default" role="navigation">
            <div class="navbar-header">
                <a class="navbar-brand" href="/">量化投資平臺</a>
            </div>

            <div class="collapse navbar-collapse navbar-ex1-collapse">
                <ul class="nav navbar-nav">
                    <li ng-repeat="a1 in navbar" class="dropdown">
                        <a href="?{{ a1.label }}" class="dropdown-toggle" data-toggle="dropdown">{{ a1.label }} <b class="caret"></b></a>
                        <ul class="dropdown-menu menu-top">
                            <li ng-repeat="a2 in a1.children" class="dropdown-submenu">
                                <a tabindex="-1" href="?{{ a2.label }}">{{ a2.label }}</a>
                                <ul ng-show="a2.children.length>0" class="dropdown-menu">
                                    <li ng-repeat="a3 in a2.children">
                                        <a href="?{{ a3.label }}" ng-click="go(a3.link)">{{ a3.label }}</a>
                                    </li>
                                </ul>
                            </li>
                        </ul>
                    </li>
                </ul>
            </div>
        </nav>
    </div>
</div>

<script src="/bower_components/jquery/dist/jquery.min.js"></script>
<script src="/bower_components/angular/angular.min.js"></script>
<script src="/bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="/bower_components/angular-route/angular-route.min.js"></script>
<script src="/bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>

<script src="/js/app.js"></script>

</body>
</html>

在Angularjs的控制器檔案app.js檔案中,增加page4的定義。


var page4 = angular.module('page4', ['ui.bootstrap', 'ngRoute']);

page4.config(['$routeProvider', '$locationProvider', '$sceProvider', function ($routeProvider, $locationProvider, $sceProvider) {
    $routeProvider
        .when('/', {controller: 'DemoCtrl'})
        .otherwise({redirectTo: '/'});
    $locationProvider.html5Mode(true);
}]);

page4.controller('NavbarCtrl', function ($scope,$http,$location) {
    $http.get("/js/nav.json").success(function(json){
        $scope.navbar = json;
    });
});

page4.controller('DemoCtrl', function () {
    // nothing
});

檢視一下顯示效果,與上面的截圖類似。

m-nav4

文章到這裡就結束了,已經實現了我的功能需求。但這個話題還有很多可以優化的地方,比如實現無限級的導航選單,選單的展示樣式替換,展示區間的控制,滑鼠動作事件,封裝成Angularjs的外掛開源專案等。有興趣的同學,可以我的程式的基礎上繼續努力,做出優秀的開源專案來。


git clone https://github.com/bsspirit/angular-navbar.git
cd angular-navbar
bower install
anywhere