1. 程式人生 > 實用技巧 >開始使用AngularJS和ASP。NET MVC -第二部分

開始使用AngularJS和ASP。NET MVC -第二部分

文章系列: 第一部分第二部分(本文)第三部分 在第一部分中,我們使用了一個基本的AngularJS/ASP。NET MVC應用程式包含以下內容: 構建一個成熟的單頁面應用程式的樣板程式碼需要一些基本的路由,包括一個包含引數的路由,以及另一個只有經過身份驗證的使用者(使用基於cookie的身份驗證)才能訪問的登入和登錄檔單的路由,包括使這些功能發揮作用所需的angular Javascript程式碼 由於懶惰/時間的限制,我在本文的第一部分末尾附上了Visual Studio解決方案。但是,我已經刪除了包目錄,使其更小,所以您將需要使用Nuget包還原來將它們恢復。 我們出色的應用程式仍然有很多問題,其中一些問題我們將在第二部分中解決。本文比第1部分更短(也不那麼令人興奮),但是將為第3部分準備好所有內容。 原始碼 本文附帶的原始碼可以在這裡找到。 第二部分我們要解決的問題 醜陋的URL -當我們在檢視之間導航時,我們會在URL中得到這個醜陋的蘇格蘭標記(#)。我們將在第二部分解決這個問題通過使用HTML5模式(pushstate)醜陋的觀點——我們甚至沒有嘗試任何樣式應用到我們的應用程式的一部分,讓我們加入Twitter引導和角UI為引導指令新增功能,而不需要jquery非常基本的路由,在第一部分我們使用ngRoute基本路由是好的,但低於當我們有更高階的需求。在第二部分中,我們將用Angular UI Router替換它 醜陋的URL 現在我們的URL看起來是這樣的: web伺服器將忽略scotch(#)之後的所有內容。我們在第1部分中新增的ngRoute目前接受URL的這一部分,檢查它是否與我們設定的任何模式匹配,如果匹配,則將正確的檢視載入到登入頁面上的容器div中。 如果我們使用AngularJS的HTML5模式,我們可以有更好的URL。這將導致Angular使用HTML5的歷史API來處理所有的複雜性,而在我們這端只需要幾行程式碼(一行Javascript和幾行c#)。 首先,我們需要修改我們的應用的配置函式,它現在有Angular's$locationProvider模組作為一個依賴項,我們稱之為hashPrefix和html5mode函式。就是這樣。 隱藏,收縮,複製Code

var configFunction = function ($routeProvider, $httpProvider, $locationProvider) {

    $locationProvider.hashPrefix('!').html5Mode(true);

    $routeProvider.
        when('/routeOne', {
            templateUrl: 'routesDemo/one'
        })
        .when('/routeTwo/:donuts', {
            templateUrl: function (params) { return '/routesDemo/two?donuts=' + params.donuts; }
        })
        .when('/routeThree', {
            templateUrl: 'routesDemo/three'
        })
        .when('/login', {
            templateUrl: '/Account/Login',
            controller: LoginController
        })
        .when('/register', {
            templateUrl: '/Account/Register',
            controller: RegisterController
        });

    $httpProvider.interceptors.push('AuthHttpResponseInterceptor');
}
configFunction.$inject = ['$routeProvider', '$httpProvider', '$locationProvider'
];

我們登陸頁面上的連結也需要更新,以刪除蘇格蘭: 隱藏,複製Code

<ul>
    <li><a href="/routeOne">Route One</a></li>
    <li><a href="/routeTwo/6">Route Two</a></li>
    <li><a href="/routeThree">Route Three</a></li>
</ul>

<ul>
    <li><a href="/login"
>Login</a></li> <li><a href="/register">Register</a></li> </ul>

很好,現在讓我們除錯站點並瀏覽: 我們的URL看起來更好,但是點選重新整理: HTML5模式正在工作,但只是以一種非常表面的方式。重新整理頁面會將完整的URL傳送到伺服器(因為我們已經刪除了scotch),而伺服器不知道該做什麼。我們可以通過正確地重新配置MVC的RouteCollection來解決這個問題。我們需要明確每個檢視的路由,然後新增一個all - catch,它會將其他所有URL傳送到我們的著陸頁面,由Angular處理。 更新App_Start =>中的RegisterRoutes方法RouteConfig.cs一樣: 隱藏,收縮,複製Code

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        name: "routeOne",
        url: "routesDemo/One",
        defaults: new { controller = "RoutesDemo", action = "One" });

    routes.MapRoute(
        name: "routeTwo",
        url: "routesDemo/Two/{donuts}",
        defaults: new { controller = "RoutesDemo", action = "Two", donuts = UrlParameter.Optional });

    routes.MapRoute(
        name: "routeThree",
        url: "routesDemo/Three",
        defaults: new { controller = "RoutesDemo", action = "Three" });

    routes.MapRoute(
        name: "login",
        url: "Account/Login",
        defaults: new { controller = "Account", action = "Login" });

    routes.MapRoute(
        name: "register",
        url: "Account/Register",
        defaults: new { controller = "Account", action = "Register" });

    routes.MapRoute(
        name: "Default",
        url: "{*url}",
        defaults: new { controller = "Home", action = "Index" });
}

再次除錯網站,瀏覽周圍,並測試後退/重新整理按鈕,一切現在應該正常工作。 醜陋的觀點 現在的網站沒有任何樣式應用。讓我們用Twitter Bootstrap來解決這個問題,我將在Cloudflare中新增它。和Angular UI引導指令一起,我將在關閉頁面之前新增這些指令。標籤。 只需應用幾個CSS類,並新增一些元素,就可以改變整個web應用程式的外觀。像這樣更新你的登陸頁面: 隱藏,收縮,複製Code

<!DOCTYPE html>
<html ng-app="AwesomeAngularMVCApp" ng-controller="LandingPageController">
<head>
    <title ng-bind="models.helloAngular"></title>
    <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.2.0/css/bootstrap.min.css">
    @Styles.Render("~/Content/css")
</head>
    <body>
        <div class="navbar navbar-default navbar-fixed-top" role="navigation">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle" ng-click="navbarProperties.isCollapsed = !navbarProperties.isCollapsed">
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    <a class="navbar-brand" href="#">Awesome Angular MVC APP</a>
                </div>
                <div class="navbar-collapse collapse" collapse="navbarProperties.isCollapsed">
                    <ul class="nav navbar-nav">
                        <li><a href="/routeOne">Route One</a></li>
                        <li><a href="/routeTwo/6">Route Two</a></li>
                        <li><a href="/routeThree">Route Three</a></li>
                    </ul>
                    <ul class="nav navbar-nav navbar-right">
                        <li><a href="/login">Login</a></li>
                        <li><a href="/register">Register</a></li>
                    </ul>
                </div>
            </div>
        </div>
        
        <div class="container mainContent">
            <div ng-view></div>
        </div>

        <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.min.js"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-route.min.js"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.10.0/ui-bootstrap-tpls.min.js"></script>
        @Scripts.Render("~/bundles/AwesomeAngularMVCApp")
    </body>
</html>

將以下內容新增到Content =>Site.css 隱藏,複製Code

.mainContent {
    margin-top: 60px;
}

現在,我們需要在Angular應用模組中為Bootstrap模組註冊Angular UI指令,我們在AwesomeAngularMVCApp.js中這樣做: 隱藏,複製Code

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

最後,我們的Angular著陸頁面控制器需要更新為移動導航選單的預設狀態(最初會被摺疊): 隱藏,複製Code

var LandingPageController = function($scope) {

    ...

    $scope.navbarProperties = {
        isCollapsed: true
    };
}

Twitter Bootstrap本身就是一個完整的主題。本節的重點是向您展示如何正確地將其新增到任何AngularJS應用程式中。 在不使用jQuery的情況下,將移動導航選單設定為正確地展開和摺疊,這是很多人都會遇到的問題,就像在應用模組中正確地註冊Angular UI引導指令一樣,所以我在這裡強調了這些問題。 現在你可以在此基礎上使用Twitter載入程式來完全設計你的站點。 非常基本的路由 我們目前使用的是AngularJS自己的ngRoute模組,這對於基本的路由是很好的,但是如果我們有更高階的路由需求,我們可能會發現outself有點受限ts。 讓我們用Angular UI路由器來替換它。這是一個完全成熟的Angular路由框架,它為我們提供了巢狀的、多檢視和命名檢視。 我們現在已經完成了足夠的準備工作,但是如果您計劃使用它來構建一個完整的單頁應用程式,那麼您需要閱讀深入指南,並將API引用儲存在附近的選項卡中以供參考。 更新你的登陸頁面,將新增ngRoute的Javascript標籤替換為Angular UI路由器的標籤: 隱藏,複製Code

<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.min.js"></script>

現在我們需要在Angular應用模組中註冊Angular UI路由器,移除ngRoute的註冊: 隱藏,複製Code

var AwesomeAngularMVCApp = angular.module('AwesomeAngularMVCApp', ['ui.router', 'ui.bootstrap']);

Angular UI路由器是基於狀態的。它基於有限狀態機的數學概念,並將您的web應用程式轉換為相同的有限狀態機。不是從一個URL導航到另一個URL,而是從一個狀態轉換到另一個狀態,並設定一個路由來表示應用程式可能處於的每個狀態。 在UI Router中,我們可以在著陸頁面上有多個容器檢視,而在ngRoute中,我們只能有一個。現在我們將新增兩個檢視到我們的著陸頁面,並設定我們的應用程式有四個狀態: 當應用程式狀態,我們將負載路線到我們第一個容器div,和路線兩個到我們的第二狀態兩個應用程式時,我們將負載路線到我們第一個容器div,和路線三到我們的第二狀態三個應用程式時,我們將路線兩個載入到第一個容器div,和路線三到我們第二LoginRegister狀態中的應用程式時,我們將我們的登入表單載入到第一個容器div,並將登錄檔轉入第二行 更新登陸頁,這樣我們現在有兩個容器div,刪除容器div,我們以前使用ngRoute: 隱藏,複製Code

<div class="container mainContent">
    <div class="row">
        <div class="col-md-6">
            <div ui-view="containerOne"></div>
        </div>
        <div class="col-md-6">
            <div ui-view="containerTwo"></div>
        </div>
    </div>
</div>

現在讓我們修改AwesomeAngularMVCApp.js來告訴它把什麼檢視放在什麼位置,在什麼狀態下。我們不再依賴ngRoute的$routeProvider 服務,而有一個新的依賴於UI路由器的$stateProvider: 隱藏,收縮,複製Code

var configFunction = function ($stateProvider, $httpProvider, $locationProvider) {

    $locationProvider.hashPrefix('!').html5Mode(true);

    $stateProvider
        .state('stateOne', {
            url: '/stateOne?donuts',
            views: {
                "containerOne": {
                    templateUrl: '/routesDemo/one'
                },
                "containerTwo": {
                    templateUrl: function (params) { return '/routesDemo/two?donuts=' + params.donuts; }
                }
            }
        })
        .state('stateTwo', {
            url: '/stateTwo',
            views: {
                "containerOne": {
                    templateUrl: '/routesDemo/one'
                },
                "containerTwo": {
                    templateUrl: '/routesDemo/three'
                }
            }
        })
        .state('stateThree', {
            url: '/stateThree?donuts',
            views: {
                "containerOne": {
                    templateUrl: function (params) { return '/routesDemo/two?donuts=' + params.donuts; }
                },
                "containerTwo": {
                    templateUrl: '/routesDemo/three'
                }
            }
        })
        .state('loginRegister', {
            url: '/loginRegister?returnUrl',
            views: {
                "containerOne": {
                    templateUrl: '/Account/Login',
                    controller: LoginController
                },
                "containerTwo": {
                    templateUrl: '/Account/Register',
                    controller: RegisterController
                }
            }
        });

    $httpProvider.interceptors.push('AuthHttpResponseInterceptor');
}
configFunction.$inject = ['$stateProvider', '$httpProvider', '$locationProvider'];

我們還需要更新AuthHttpResponseInterceptor,使其在伺服器返回401響應時進入loginRegister狀態。要實現這一點,我們需要注入UI路由器的$state服務。然而,由於這個庫中的一個bug,我們不能直接注入它。相反,我們注入了AngularJS的$injector服務,並用它來解析一個$state的例項: 隱藏,複製Code

var AuthHttpResponseInterceptor = function($q, $location, $injector) {
    return {
        response: function (response) {
            if (response.status === 401) {
                console.log("Response 401");
            }
            return response || $q.when(response);
        },
        responseError: function (rejection) {
            if (rejection.status === 401) {
                $injector.get('$state').go('loginRegister', { returnUrl: $location.path() });
            }
            return $q.reject(rejection);
        }
    }
}

AuthHttpResponseInterceptor.$inject = ['$q', '$location', '$injector'];

我們的LoginController也需要更新,因為它現在從UI路由器的$stateParams物件中提取返回的URL,而不是ngRoute的$routeParams物件: 隱藏,複製Code

var LoginController = function ($scope, $stateParams, $location, LoginFactory) {
    $scope.loginForm = {
       ...etc
        returnUrl: $stateParams.returnUrl,
        ...etc
    };

   ...etc
}

LoginController.$inject = ['$scope', '$stateParams', '$location', 'LoginFactory'];

最後,我們需要更新連結。有趣的是,我們的超連結不再以URL為中心,現在我們直接連結到狀態本身,並使用JSON提供該狀態的任何引數。更新登陸頁面上的連結,使其看起來像這樣: 隱藏,複製Code

<div class="navbar-collapse collapse" collapse="navbarProperties.isCollapsed">
    <ul class="nav navbar-nav">
        <li><a ui-sref="stateOne({ donuts: 12 })">State One</a></li>
        <li><a ui-sref="stateTwo">State Two</a></li>
        <li><a ui-sref="stateThree({ donuts: 4 })">State Three</a></li>
    </ul>
    <ul class="nav navbar-nav navbar-right">
        <li><a ui-sref="loginRegister">Login / Register</a></li>
    </ul>
</div>

現在讓它進行除錯和瀏覽。航行到一個應該返回路線1和2,並排: 如果我們嘗試導航到狀態2或狀態3,攔截器將像以前一樣介入,並將我們轉換到loginregisterstate。如果我們在此時登入,我們還可以檢視狀態2和狀態3。 巢狀檢視 我們還沒有討論巢狀檢視。讓我們向我們的RoutesDemo控制器新增另一個c#動作方法Four,並使用Visual Studio建立檢視。向此檢視新增一些內容以惟一地標識它。現在還要從路由3中刪除Authorize屬性,這只是為了演示一個概念。 我們將把路徑4巢狀在路徑1裡面,所以像這樣更新路徑1的檢視: 隱藏,複製Code

Route one

<div ui-view="nestedView"></div>

現在讓我們更新Angular中的路由配置來反映這一點。在向狀態新增巢狀檢視時,我們使用命名配置viewName@stateName。為了為stateOne配置nestedView我們給它命名為nestedView@stateOne,像這樣: 隱藏,複製Code

    $stateProvider
        .state('stateOne', {
            url: '/stateOne?donuts',
            views: {
                "containerOne": {
                    templateUrl: '/routesDemo/one'
                },
                "containerTwo": {
                    templateUrl: function (params) { return '/routesDemo/two?donuts=' + params.donuts; }
                },
                "nestedView@stateOne": {
                    templateUrl: '/routesDemo/four'
                }
            }
        })
        .state('stateTwo', 
        ...etc

我們剛剛添加了一個新檢視,因此需要更新routeconfig來反映這一點: 隱藏,複製Code

routes.MapRoute(
    name: "routeFour",
    url: "routesDemo/Four",
    defaults: new { controller = "RoutesDemo", action = "Four" });

現在讓我們來測試一下: 回顧 在第二部分中我們實現了以下內容: 在AngularJS中啟用HTML5模式(pushstate),必要時配置MVC,新增Twitter Bootstrap和Angular UI引導。現在我們可以從這些庫中新增元件了,我們需要用Angular UI router替換ngRoute,並在應用程式中新增命名、多檢視和巢狀檢視。 接下來是第三部分 訊號整合指令反偽造令牌 評論/批評/問題等 如果有任何評論/批評/問題,請對這篇文章發表評論,我會回覆你的。謝謝閱讀:) 本文轉載於:http://www.diyabc.com/frontweb/news1678.html