18、AngularJS:服务、服务器通信与视图组织

AngularJS:服务、服务器通信与视图组织

1. 服务与服务器通信

在处理异步通信时,我们常常需要考虑代码的放置位置以及数据的处理和错误处理。

1.1 代码放置位置

不能将代码放在 success 方法中,因为如果出现错误,表单会陷入工作状态,导致用户界面冲突。可以将代码同时放在 success error 方法中,但更好的方式是使用 promise 对象的 finally 方法。无论 promise 被拒绝还是完成, finally 方法都会被调用。

1.2 处理返回数据

异步通信往往不只是简单地发送数据,还需要处理服务器的响应数据。例如,用户名查找服务可能需要检查返回值,以确定给定的用户名是否存在于系统中。

promise.success(function (data, status) {
    $scope.successMessage = "Your transaction identifier is " + data.transactionID;
    $scope.showSuccessMessage = true;
});

这个例子假设从服务器收到了一个 JSON 响应,结构类似 {"transactionID": "12587965"} 。在实际项目中,可能会遇到不同的结构和格式,如 XML。

1.3 错误处理

应用程序会因为各种原因产生错误,有些可能与网络相关,有些可能是代码错误或配置问题。可以在 promise 对象的 error 方法中进行错误处理。

promise.error(function (data, status) {
    if (status === 0) {
        $scope.errorMessage = "network or http level issue";
    } else {
        $scope.errorMessage = "response HTTP status is " + status;
    }
    $scope.showErrorMessage = true;
});

这里使用了 status 参数,它会提供 HTTP 状态码,告诉我们服务器的响应情况。状态码在 200 到 299 之间被认为是成功的,在错误回调中不会看到这个范围内的状态码。如果服务器由于网络或 HTTP 级别的问题根本没有响应,会得到 0 作为结果。

2. 组织视图

AngularJS 在创建单页应用(SPA)方面表现出色。随着 HTML5 的发展和更快的互联网连接,SPA 变得越来越普遍。但在单页请求中下载大量内容时,会面临内容组织和管理的问题,Angular 路由系统可以很好地解决这个问题。

2.1 安装 ngRoute 模块

Angular 路由系统定义在可选模块 ngRoute 中,需要先下载并安装该模块。操作步骤如下:
1. 访问 http://angularjs.org
2. 点击 Download
3. 选择所需的版本(这里使用 1.2.5 版本)。
4. 点击 Extras 旁边显示的 Browse additional modules 链接。
5. 下载 angular-route.js 文件(或压缩版本 angular-route.min.js )到 angularjs 文件夹。

在新的 HTML 文件中添加对 angular-route.js 文件的引用:

<!DOCTYPE html>
<html ng-app="myApp">
<head>
<title></title>
<script src="angular.js"></script>
<script src="angular-route.js"></script>
</head>
<body>
<!-- body code here -->
</body>
</html>
2.2 使用 URL 路由

通过创建一个包含主页、关于页面和联系页面的小网站来学习路由。传统的静态 HTML 网站会将这些内容结构化为三个单独的 HTML 文件,但使用 Angular 路由系统可以将这些页面注入到单个容器或父视图页面中。

定义路由时,核心是 $route 服务,它允许创建 URL 和视图文件名之间的映射。例如:

$routeProvider.when('/about', {
    templateUrl: 'pages/about.html',
    controller: 'aboutController'
});

这个路由表示当 URL 的路径为 /about 时,加载视图模板 pages/about.html ,并使用 aboutController

下面是一个更完整的示例,展示了如何配置路由:

<!DOCTYPE html>
<html ng-app="app">
<head>
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"/>
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.0/css/font-awesome.css"/>
    <script src="angular.min.js"></script>
    <script src="angular-route.js"></script>
    <script>
        var app = angular.module('app', ['ngRoute']);
        app.config(function ($routeProvider) {
            $routeProvider
              .when('/', {
                    templateUrl: 'pages/home.html',
                    controller: 'homeController'
                })
              .when('/pages/about', {
                    templateUrl: 'pages/about.html',
                    controller: 'aboutController'
                })
              .when('/pages/contact/', {
                    templateUrl: 'pages/contact.html',
                    controller: 'contactController'
                })
              .otherwise({
                    templateUrl: 'pages/routeNotFound.html',
                    controller: 'notFoundController'
                });
        });

        app.controller('homeController', function ($scope) {
            $scope.message = 'Welcome to my home page!';
        });

        app.controller('aboutController', function ($scope) {
            $scope.message = 'Find out more about me.';
        });

        app.controller('contactController', function ($scope) {
            $scope.message = 'Contact us!';
        });

        app.controller('notFoundController', function ($scope) {
            $scope.message = 'There seems to be a problem finding the page you wanted';
            $scope.attemptedPath = $location.path();
        });
    </script>
</head>
<body ng-controller="homeController">
<header>
    <nav class="navbar navbar-default">
        <div class="container">
            <div class="navbar-header">
                <a class="navbar-brand" href="/">My Website</a>
            </div>
            <ul class="nav navbar-nav navbar-right">
                <li><a href="#"><i class="fa fa-home"></i> Home</a></li>
                <li><a href="#about"><i class="fa fa-shield"></i> About</a></li>
                <li><a href="#contact"><i class="fa fa-comment"></i> Contact</a></li>
            </ul>
        </div>
    </nav>
</header>
<div id="main">
    <div ng-view></div>
</div>
</body>
</html>

在这个示例中,我们配置了四个路由:主页、关于页面、联系页面和路由未找到页面。每个路由都指定了对应的视图模板和控制器。

下面是不同 URL 下 $location 服务的方法表现:
| URL | $location.path() | $location.url() | $location.absUrl() |
| — | — | — | — |
| http://localhost:63342/index.html#/ | / | / | http://localhost:63342/index.html#/ |
| http://localhost:63342/index.html#/about | /about | /about | http://localhost:63342/index.html#/about |
| http://localhost:63342/index.html#/contact?someParam=someValue | /contact | /contact?someParam=someValue | http://localhost:63342/index.html#/contact?someParam=someValue |

路由系统通过比较 $location.path() 的值和路由定义来确定加载哪个视图模板。当用户与导航链接交互时,当前路由会发生变化,从而加载不同的视图。

graph LR
    A[用户访问 URL] --> B{匹配路由}
    B -->|匹配成功| C[加载对应视图模板]
    B -->|匹配失败| D[加载 routeNotFound.html]
3. 视图模板

以下是四个视图模板的代码:

<!-- 主页 -->
<div class="jumbotron text-center">
    <h1>Home Page</h1>
    <p>{{ message }}</p>
    <div>
    </div>
</div>
<!-- 关于页面 -->
<div class="jumbotron text-center">
    <h1>About Page</h1>
    <p>{{ message }}</p>
    <div>
    </div>
</div>
<!-- 联系页面 -->
<div class="jumbotron text-center">
    <h1>Contact Page</h1>
    <p>{{ message }}</p>
    <div>
    </div>
</div>
<!-- 路由未找到页面 -->
<div class="jumbotron text-center">
    <h1>This is not good</h1>
    <p>{{message}}</p>
    <p class="has-error">{{attemptedPath}}</p>
</div>

这些视图模板使用了 Bootstrap 定义的类来帮助布局。在路由未找到页面中,使用了 has-error 类将尝试的路径标记为红色,以突出错误输入。

4. 控制器

为每个路由定义指定了控制器,除了最后一个控制器,其他控制器只是设置了 $scope.message 的值,以便区分不同页面。

app.controller('homeController', function ($scope) {
    $scope.message = 'Welcome to my home page!';
});

app.controller('aboutController', function ($scope) {
    $scope.message = 'Find out more about me.';
});

app.controller('contactController', function ($scope) {
    $scope.message = 'Contact us!';
});

在配置路由时,需要注意以下几点:
- 声明依赖 ngRoute 模块,否则路由系统无法正常工作。
- 使用应用模块的 config() 方法设置路由配置,该方法只能使用 $routeProvider 而不是 $route 服务,因为 config() 方法比较特殊,只能使用提供者。
- 路由提供者的 when() 方法添加新的路由定义,注意路径的前向斜杠,不同的路径可能导致不同的匹配结果。
- 当无法匹配任何路由时,使用 otherwise() 方法显示路由未找到页面。

通过以上的步骤和示例,我们可以看到如何使用 AngularJS 的服务、服务器通信和路由系统来构建一个功能强大且易于管理的单页应用。

AngularJS:服务、服务器通信与视图组织

5. 路由配置注意事项

在进行路由配置时,有一些重要的注意事项需要牢记,以确保路由系统的正常运行。

  • 依赖声明 :创建应用模块时,必须声明对 ngRoute 模块的依赖,否则路由系统将无法工作。示例代码如下:
var app = angular.module('app', ['ngRoute']);
  • config() 方法与提供者 :使用应用模块的 config() 方法来设置路由配置,此方法只能使用提供者,而不是服务。所以要使用 $routeProvider 来配置路由。例如:
app.config(function ($routeProvider) {
    // 配置路由
    $routeProvider
      .when('/', {
            templateUrl: 'pages/home.html',
            controller: 'homeController'
        })
      .when('/pages/about', {
            templateUrl: 'pages/about.html',
            controller: 'aboutController'
        })
      .when('/pages/contact/', {
            templateUrl: 'pages/contact.html',
            controller: 'contactController'
        })
      .otherwise({
            templateUrl: 'pages/routeNotFound.html',
            controller: 'notFoundController'
        });
});
  • when() 方法路径注意 routeProvider when() 方法用于添加新的路由定义,路径中的前向斜杠非常重要。例如, /pages/about pages/about 是不同的路径,缺少前向斜杠可能会在导航网站时导致 Not found 错误。

  • otherwise() 方法的使用 :当无法匹配任何路由时,使用 otherwise() 方法显示路由未找到页面,以提供更好的用户体验。

6. 路由系统工作流程总结

下面通过一个 mermaid 流程图更直观地展示路由系统的工作流程:

graph LR
    A[用户访问网站] --> B[加载 index.html]
    B --> C{用户点击导航链接}
    C -->|是| D[更新 $location.path() 值]
    C -->|否| B
    D --> E{匹配路由}
    E -->|匹配成功| F[加载对应视图模板和控制器]
    E -->|匹配失败| G[加载 routeNotFound.html 和 notFoundController]
    F --> H[更新页面内容]
    G --> H

从流程图可以看出,用户访问网站首先加载 index.html ,当用户点击导航链接时, $location.path() 的值会更新,路由系统会根据这个值去匹配路由。如果匹配成功,就加载对应的视图模板和控制器,并更新页面内容;如果匹配失败,则加载路由未找到页面。

7. 实际应用中的考虑

在实际应用中,除了上述的基本配置和流程,还需要考虑以下方面:

  • 错误处理的优化 :目前的错误处理代码只是简单地显示错误信息,在实际应用中,可以根据不同的错误类型提供更详细的错误提示和解决方案,以提高用户体验。例如,可以根据不同的 HTTP 状态码显示不同的错误信息:
promise.error(function (data, status) {
    if (status === 404) {
        $scope.errorMessage = "请求的页面不存在,请检查 URL。";
    } else if (status === 500) {
        $scope.errorMessage = "服务器内部错误,请稍后再试。";
    } else if (status === 0) {
        $scope.errorMessage = "网络或 HTTP 级别问题,请检查网络连接。";
    } else {
        $scope.errorMessage = "响应 HTTP 状态是 " + status;
    }
    $scope.showErrorMessage = true;
});
  • 路由参数的使用 :在实际应用中,可能需要传递参数到路由中。例如,在一个博客网站中,可能需要根据文章的 ID 来显示具体的文章内容。可以在路由配置中使用参数,示例如下:
$routeProvider.when('/article/:articleId', {
    templateUrl: 'pages/article.html',
    controller: 'articleController'
});

在控制器中可以通过 $routeParams 来获取参数:

app.controller('articleController', function ($scope, $routeParams) {
    $scope.articleId = $routeParams.articleId;
    // 根据 articleId 获取文章内容
});
  • 性能优化 :随着应用的增长,可能会有大量的视图模板和控制器,这会影响应用的性能。可以采用懒加载的方式,只在需要时加载视图模板和控制器,以减少初始加载时间。
总结

AngularJS 的服务、服务器通信和路由系统为构建单页应用提供了强大的功能。通过合理使用这些功能,可以将复杂的逻辑从模型和视图逻辑中分离出来,提高代码的可维护性和可扩展性。在实际应用中,需要注意路由配置的细节,优化错误处理,合理使用路由参数,并考虑性能优化等方面,以构建出高效、稳定且用户体验良好的单页应用。

通过以下表格总结本文的主要内容:
| 主题 | 主要内容 |
| — | — |
| 服务与服务器通信 | 处理异步通信时,使用 promise 对象的 finally 方法处理通用任务;通过 success 方法处理返回数据, error 方法处理错误 |
| 组织视图 | 安装 ngRoute 模块,使用 $route 服务定义 URL 和视图文件名的映射,通过 ngView 指令加载视图模板 |
| 路由配置注意事项 | 声明 ngRoute 依赖,使用 $routeProvider config() 方法中配置路由,注意路径的前向斜杠和 otherwise() 方法的使用 |
| 实际应用考虑 | 优化错误处理,使用路由参数,进行性能优化 |

希望通过本文的介绍,你对 AngularJS 的服务、服务器通信和路由系统有了更深入的理解,并能够运用这些知识构建出优秀的单页应用。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值