• 开始使用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

  • 相关阅读:
    linux-常用命令
    linux
    测试基础
    链家笔试1
    链家笔试2
    链家笔试3
    MySql优化
    Http1.1和Http2.0
    Charles学习
    链表中倒数第k个结点
  • 原文地址:https://www.cnblogs.com/Dincat/p/13456300.html
Copyright © 2020-2023  润新知