65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 ES6 JavaScript 和模块创建 AngularJS 应用程序

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2021年3月9日

MIT

13分钟阅读

viewsIcon

7563

downloadIcon

107

如何使用 ES6 JavaScript 和模块创建 AngularJS 应用程序

引言

去年年底,我一直在思考未来。未来已来。但有时很难迈出这一步并拥抱未来。学习一项新技能,并掌握到足以用于新项目需要花费大量时间和精力。这就是我一直不愿意学习node.js的原因。它支持的项目开发类型往往需要花费太长时间才能精通。很可能,我需要同时学习五件不同的事情,结果也不会好。学习将分散对开发的注意力。但我希望继续前进,并在开发中使用现代 JavaScript 语言。所以我想,是否可以在不处理 node.js 的情况下,使用基于 ES6 语法的 JavaScript 和 AngularJS 来开发应用程序?事实证明,这是可能的。本教程将讨论如何实现。

这是我想要做的。我想要创建一个单页 AngularJS 应用程序,并使用基于 ES6 的 JavaScript 语法,不使用 node.js。如前所述,这是可行的,而且很容易实现。我确实花了几小时进行研究。总之,本教程将逐步指导你完成实现,并介绍如何使用 ES6 脚本语法编写 AngularJS。

示例应用程序架构

本教程的示例应用程序使用 Spring Boot 创建了一个基于 Web 的应用程序。它所做的只是向用户提供静态内容,如 HTML 页面、样式表和 JavaScript 文件。这是一个单页应用程序,有四个可导航的子页面。第一个子页面是 index,它只是一个静态显示页面。第二个页面将显示控制器中的一个 string 值,以及一个按钮,该按钮的 click 事件由控制器对象的某个方法处理。另外两个页面是 static 的,也仅用于显示目的。

整个想法是展示如何使用 ES6 脚本创建一个 JavaScript 对象。这个控制器(通俗地说)连接到视图(页面模板),并可以在视图和控制器之间交换数据。此外,该应用程序还将展示如何设置页面模板的导航。最后,将这两者结合到一个应用程序中。这些是 AngularJS 应用程序最基本的功能。如果这些可以使用 ES6 脚本完成,那么就可以使用相同的语法编写一个完整的应用程序。难点在于弄清楚如何实现。事实证明,这些都不难。所有需要的就是一点研究。

入口页面

我将从入口页面开始。有一点需要强调。为了在我的应用程序中使用 ES6 脚本语法,我需要将 JavaScript 文件添加为模块,而不是普通脚本文件。让我向你展示区别。这是一个我添加到 HTML 页面的普通脚本文件。

...
<script type="text/javascript" src="/assets/jquery/js/jquery.min.js"></script>
...

为了将 JavaScript 文件添加为模块,我必须这样做。

...
<script type="module" src="/assets/app/js/TestController.js"></script>
...

这是必需的,因为根据文档,Chrome 和 FireFox 可以执行 ES6 语法兼容的脚本,如果该文件被添加为模块。好了。这是使用基于 ES6 语法的第一个步骤。

让我向你展示这个入口页面的其余部分。我们之所以称这些 AngularJS 应用程序为单页应用程序,是因为只有一个页面,这个页面的内容会根据放置在这个页面上的模板而改变。这个入口页面是位于 src/main/resources/static/ 子目录下的 index.html 文件。有一个非常基本的导航菜单。

<div class="row">
   <div class="col-0xs-12">
      <ul class="nav nav-pills">
         <li role="presentation"><a href="./#!/">Home</a></li>
         <li role="presentation"><a href="./#!/red">Red Page</a></li>
         <li role="presentation"><a href="./#!/green">Green Page</a></li>
         <li role="presentation"><a href="./#!/blue">Blue Page</a></li>
      </ul>
   </div>
</div>

这是一个非常简单的导航菜单,只有 4 个链接。如果你是第一次使用 AngularJS,导航的工作方式是使用像这样的链接:“./#!/<angularjs-links>”,即“./#!/blue”。这些是 AngularJS 路由可以识别并正确渲染页面的 URL 重写规则。

由于我们使用的是 AngularJS 路由而不是花哨的 ui-router(一个与 AngularJS 配合使用的第三方组件),我们需要指定一个区域来渲染子页面。这是如何做到的。

<div class="row">
   <div class="col-xs-12">
      <div class="panel panel-default">
         <div class="panel-body">
            <ng-view></ng-view>
         </div>
      </div>            
   </div>
</div>

页面将作为 <ng-view/> 标签的子元素渲染。

每个 AngularJS 应用程序都有一个入口点,一个被指定为 ngAppngModule。这在 HTML 页面的顶部定义,如下所示。

<div class="container top-margin" ng-app="startup">
...
</div>

最后,我将 JavaScript 文件和模块添加到这个网页。就像这样。

...
<script type="text/javascript" src="/assets/jquery/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/angularjs/1.7.5/angular.min.js"></script>
<script type="text/javascript" src="/assets/angularjs/1.7.5/angular-resource.min.js"></script>
<script type="text/javascript" src="/assets/angularjs/1.7.5/angular-route.min.js"></script>      
<script type="module" src="/assets/app/js/app.js"></script>
...

前几行是为 AngularJS 源代码添加的 JavaScript 文件。最后一行是我 AngularJS 应用程序入口的模块。我不用列出所有其他模块,因为这个文件和随后的模块文件都是相互连接的。它们相互导入并创建引用链接,所以不需要在这里添加每个 JS 文件。

除了这个基础 HTML 文件,还有四个 HTML 文件,每个文件代表一个子页面。其中一个也称为 index.html。它是默认显示的页面,其他页面的名称是一个颜色,名为“red”的页面包含一些交互式元素,以演示如何为页面创建控制器。另外两个页面是静态的。它们用于演示路由功能。

在下一节中,我将向你展示我的 JavaScript 模块代码是如何工作的。这包括应用程序入口、路由配置和测试控制器。

应用程序模块

每个 AngularJS 应用程序都必须有一个定义的模块,并被指定为 ngApp 的值。我已经展示了如何做到这一点。让我再次向你展示。

<div class="container top-margin" ng-app="startup">
...
</div>

这个“startupngModule 定义在名为 app.js 的文件中。其内容如下。

import { appRouting } from '/assets/app/js/app-routing.js';
import { TestController } from '/assets/app/js/TestController.js';

let app = angular.module('startup', ["ngRoute"]);
app.config(appRouting);
app.controller("TestController", TestController);

正如你所见,这看起来与我过去编写的 JavaScript 代码有些不同。这个文件代表了一个 ES6 意义上的模块。我使用新的 ES6 语法将对象(类对象或函数)从一个模块导入到当前模块。前两行是从其他模块导入单个对象。第一行从模块“/assets/app/js/app-routing.js”导入一个名为 appRouting 的函数。第二行导入一个类 TestController 的对象。最后三行是将这些对象注入到 AngularJS 的启动调用过程中。第一行创建一个名为“app”的对象。它是一个 AngularJS 模块。该模块名为“startup”。这是 HTML 页面上 ngApp 引用的名称。“app”调用了两个方法。第一个称为 .config()。这是我传递 appRouting 函数(从 app-routing.js 导入)的地方。这基本上是让 AngularJS 调用我的函数来设置子路径路由。最后一行是让“app”对象调用 .controller() 函数来注册名为“TestController”的控制器。这就像一个 IOC 容器,将该对象添加为一个控制器,以便视图(HTML 页面)和 AngularJS 内部能够正确引用该控制器。这个模块没有什么特别之处,所有内容都是应用程序启动的配置。

接下来,我将向你展示 appRouting 函数是如何定义的。为了为应用程序设置子页面导航,我需要将 ngRoute 模块中的一个 AngularJS 组件 $routeProvider 注入到我的 appRouting() 函数中。在定义模块 app 时,该模块已在 app.js 中注入。这里是。

...
let app = angular.module('startup', ["ngRoute"]);
...

我的“appRouting”的整个源代码如下。

export function appRouting($routeProvider) {
  $routeProvider.when("/", {
    templateUrl : "/assets/app/pages/index.html"
  });
  
  $routeProvider.when("/red", {
    templateUrl : "/assets/app/pages/page1.html",
    controller: "TestController",
    controllerAs: "vm"
  });
  
  $routeProvider.when("/green", {
    templateUrl : "/assets/app/pages/page2.html"
  });
  
  $routeProvider.when("/blue", {
    templateUrl : "/assets/app/pages/page3.html"
  });
}

除了依赖注入的工作方式之外,这个函数非常简单。我所做的就是创建一个名为 appRouting 的函数。它接受一个名为 $routeProvider 的参数。这个参数看起来有点奇怪。我特意这样声明它,这里就是依赖注入发生的地方。如果我将参数命名为它本身,那么依赖注入就会正确发生。如果我使用不同的名称,当这个参数第一次使用时,将会发生一个 null 引用异常。

我调用 $routeProvider.when() 方法来设置子页面导航。此方法接受一个对象作为参数。该对象的属性决定了子页面的行为。有四个调用,用于设置四个不同的子页面。其中三个看起来相似。所有对象都只包含一个名为“templateUrl”的属性。我在这里做的是指定 AngularJS 将这些三个页面显示为静态页面。还有另一个调用,参数包含三个属性:“templateUrl”、“controller”和“controllerAs”。“templateUrl”属性指定了模板页面的文件位置。“controller”属性指定了该页面的 AngularJS 控制器的名称。“controllerAs”属性指定了在模板页面中引用控制器时使用的别名。 AngularJS 的最新版本倾向于使用别名来访问控制器类的模型属性。如果你不想使用这个,那么替代方法是使用“$scope”来访问控制器模型属性。这已经不再推荐了。

export 关键字用于导出函数,以便其他 JavaScript 模块可以导入它。现在子页面导航配置已经讨论完毕,接下来,我们将讨论 TestController 的设计。

对于这个应用程序,我只需要创建一个非常简单的应用程序,其中有一个页面与一个控制器相关联。控制器应该有几个属性,它们是模型属性(可以在页面上使用),可以在页面上进行操作。然后会有一个按钮,用户可以点击该按钮并在页面上看到响应。这些应该足以演示使用 ES6 语法设计控制器的想法。

对于这个控制器,我将设计一个简单的加法计算器。将有两个输入字段供用户输入整数值。然后将有另一个输入字段显示这两个输入值的总和。如果用户输入了无效值,那么显示总和的输入字段将重置为 null,然后将显示警告。为了进行输入验证和计算总和,用户将点击名为“Calculate”的按钮。

这是控制器的完整源代码。

export class TestController {
  
  constructor() {
    this._value1 = "";
    this._value2 = "";
    this._sumValue = null;
  }
  
  get value1 () {
     return this._value1;
  }
  
  set value1 (val) {
     this._value1 = val;
  }
  
  get value2 () {
     return this._value2;
  }
  
  set value2 (val) {
     this._value2 = val;
  }
  
  get sumValue () {
     return this._sumValue;
  }
  
  set sumValue (val) {
     this._sumValue = val;
  }

  clickIt() {
     let intVal1 = parseInt(this.value1);
     let intVal2 = parseInt(this.value2);
     
     if (isNaN(intVal1) || isNaN(intVal2)) {
        alert("The integer values entered is/are invalid. Please correct.");
        this.sumValue = null;
        return;
     }
     
     this.sumValue = intVal1 + intVal2;
  }
}

这个类非常简单。它有三个属性和一个 public 方法。让我向你展示它们是什么。首先,这些是属性,它们在类的构造函数中声明和初始化。

...
  constructor() {
    this._value1 = "";
    this._value2 = "";
    this._sumValue = null;
  }
...

暴露这些属性的一种好方法是通过 getter 和 setter(也称为访问器)。这些 getter 和 setter 是。

...
  get value1 () {
     return this._value1;
  }
  
  set value1 (val) {
     this._value1 = val;
  }
  
  get value2 () {
     return this._value2;
  }
  
  set value2 (val) {
     this._value2 = val;
  }
  
  get sumValue () {
     return this._sumValue;
  }
  
  set sumValue (val) {
     this._sumValue = val;
  }
...

最后,这个类的 public 方法用于处理视图上的按钮点击事件。这是。

...
  clickIt() {
     let intVal1 = parseInt(this.value1);
     let intVal2 = parseInt(this.value2);
     
     if (isNaN(intVal1) || isNaN(intVal2)) {
        alert("The integer values entered is/are invalid. Please correct.");
        this.sumValue = null;
        return;
     }
     
     this.sumValue = intVal1 + intVal2;
  }
...

仔细看看这个方法。它首先尝试将文本字段的值解析为整数。然后它检查解析后的值,确保它们是有效的数字。如果它们不是有效的数字,将会弹出一个警报框,总和值将被设置为空,并且不会执行进一步的操作。如果值有效,将计算两个值的总和并分配给 sumValue 属性。一旦成功分配值,总和的文本字段将立即更新。

如所示,类本身很简单。那么,它如何在 AngularJS 示例应用程序的视图中使用呢?事实证明,使用也非常简单。这是视图页面的源代码。

<div class="row">
   <div class="col-xs-12 col-sm-offset-2 col-sm-8 col-md-offset-3 col-md-6">
     <p><input ng-model="vm.value1"> + <input ng-model="vm.value2"> = 
     <input ng-model="vm.sumValue" readonly> <button class="btn btn-primary" 
     ng-click="vm.clickIt()">Calculate</button></p>
   </div>
</div>
<div class="row">
   <div class="col-xs-3" style="background-color: red;">
    
   </div>
</div>

这些属性的引用方式与旧方式相同。我已经将控制器对象指定为“vm”。因此,这些属性可以在视图上作为“vm.<propertyName>”来引用。这里是将属性绑定到 Value #1、Value #2 和 Sum 的文本字段的方式。

...
<input ng-model="vm.value1"> + <input ng-model="vm.value2"> = 
<input ng-model="vm.sumValue" readonly>
...

这里的标记是为了设置值 #1 加上值 2 的显示,以获得这两个值的总和。还有一个按钮可以点击来计算这两个值的总和。点击后,这两个值将被转换为整数,然后这两个值的总和存储在 sumValue 属性中。这将导致显示总和的文本字段。此按钮的定义如下。

...
<button class="btn btn-primary" ng-click="vm.clickIt()">Calculate</button>
...

如何测试示例应用程序

下载示例源代码后,请将其解压缩到安全位置。然后将所有 JavaScript 文件从 *.sj 重命名为 *.js。然后就可以编译和打包了。请注意,自今年年初以来,我已从 Java 8 切换到 Java 14。请使用 Java 14 或修改 POM 文件,以便项目可以使用 Java 8 进行编译。

使用以下命令编译和打包应用程序。

mvn clean install

编译和打包成功后,使用以下命令启动应用程序。

java -jar target/hanbo-angular-es6sample2-1.0.1.jar

应用程序成功启动后,您可以使用以下 URL 在浏览器中运行该应用程序。请使用 Chrome 或 Firefox 来运行此应用程序。我相信这也可以在基于 WebKit 的 Internet Explorer 中运行。这个从未经过测试。页面显示后,您将看到与第一个截图相同的页面显示。我在这里再次发布这张截图。

截图显示的是此应用程序的 index 子页面。还有三个页面,“Red Page”、“Green Page”和“Blue Page”。“Green Page”和“Blue Page”与 index 页面类似,它们是静态的。“Red Page”是包含加法计算逻辑的页面。这是“Red Page”的截图。

这是“Green Page”的截图。

这是“Blue Page”的截图。

就是这样。玩得开心!

摘要

又一篇教程完成了。我很享受这一篇。这是一个简单的 Web 应用程序。我设计它的目的是演示 ES6 的新语法,并将其与 AngularJS 集成。对于这个应用程序,我有两个关注点,一是弄清楚如何设置导航路由,二是弄清楚如何使用新语法配置和使用 AngularJS 控制器。经过一些研究,这两者都得到了解决,而且麻烦不大,正如我在本教程中所展示的。

然而,可以从本教程衍生出更多的教程。最常见的用法是在 AngularJS 中使用 factory 来创建服务对象。我可能会为此做一个小型教程。使用 AngularJS 创建 directive/component 也是一种常见的用法,这可以成为另一篇教程。我想我可以在今年晚些时候推出的一个教程中结合这两者,并使用 ES6 模块。总之,从现在到今年年底,我将发布许多优质教程,请经常查看我的 CodeProject 个人资料页面以获取新教程。感谢您的阅读!

历史

  • 2021 年 3 月 9 日:初稿
使用 ES6 JavaScript 和模块创建 AngularJS 应用程序 - CodeProject - 代码之家
© . All rights reserved.