核心要点
AngularJS 凭借其先进的理念迅速成为最受瞩目的 JavaScript 框架之一,这并非偶然。在 Google 的支持和开发下,AngularJS 对前端的处理方式起初可能看起来有些奇怪,但您很快就会想知道为什么以前要采用其他方式。AngularJS 使开发者能够编写前端代码,无需直接操作 DOM。本教程将指导您入门,通过构建一个使用指令和数据绑定来定义动态视图和控制器的应用程序。如果您熟悉 CoffeeScript(AngularJS 不需要),您会对本文更感兴趣,但掌握 JavaScript 基础知识就足够了。您可能以前见过很多待办事项应用程序,所以让我们构建一些有趣的东西——井字棋!我们将从标记棋盘开始。AngularJS 声称扩展 HTML 的词汇表,而不是将 DOM 隐藏在 JavaScript 后面。其理念是 HTML 本身就相当出色,但我们可以添加一些元素和属性,以构建您已经熟悉的强大、动态的模板语言。我们的棋盘只是一个简单的表格。如果我们通过良好的愿望进行编程,我们实际上只需要迭代棋盘,为每个单元格输出一个单元格即可。实际代码非常接近我们的设想:
<code class="language-html"><table> <tr ng-repeat="row in board.grid"> <td ng-repeat="cell in row"> {{ cell.marker }} </td> </tr> </table></code>
等等,那些奇怪的 ng 元素和胡须括号是什么?让我们退一步,一步一步来。
<tr ng-repeat="row in board.grid"> <p></p> <h2>AngularJS 指令</h2> <p><code>ng-repeat
是 AngularJS 的一个 指令,是提供的 HTML 扩展之一。它允许我们迭代集合,为每个项目实例化模板。在本例中,我们告诉 AngularJS 为board
对象的grid
属性中的每一行重复<tr>。假设 <code>grid
是一个二维数组,board
是窗口上的一个对象。<code class="language-html"><table> <tr ng-repeat="row in board.grid"> <td ng-repeat="cell in row"> {{ cell.marker }} </td> </tr> </table></code>然后,我们使用另一个
ng-repeat
指令迭代行中的单元格。这里的双大括号表示使用 AngularJS 数据绑定 的一个 表达式——<td> 的内容将被替换为相应单元格的 <code>marker
属性。到目前为止,很简单,对吧?您可以立即了解生成的标记将是什么样子。我们不需要使用 jQuery 等重量级工具来创建新元素并填充它们,我们只需明确我们的模板即可。这更易于维护——我们只需查看 HTML 即可确切知道 DOM 将如何更改,而无需跟踪我们实际上不记得编写的一些模糊的 JavaScript 代码。
现在我们可以可视化棋盘的状态,我们将通过定义
board
的实际内容为其提供数据源。<code class="language-html"><tr ng-repeat="row in board.grid"> <p>我们首先添加一些 JavaScript 代码,为我们的应用程序定义一个 AngularJS 模块。第一个参数是应用程序的名称,<code>['ng']</code> 表示我们需要 AngularJS 的“ng”模块,该模块提供核心 AngularJS 服务。</p> <p>我们将 HTML 调整为使用 <code>ng-app</code> 指令指示我们将使用我们的应用程序模块。</p> <pre class="brush:php;toolbar:false"><code class="language-html"><td ng-repeat="cell in row"> {{ cell.marker }} </td></code>MVC——定义控制器和视图
AngularJS 的 MVC 特性在这里发挥作用。我们添加一些 JS 代码来调用我们新创建的应用程序模块上的控制器函数,传递控制器的名称和实现它的函数。
<code class="language-javascript">app = angular.module('ngOughts', ['ng'])</code>在本例中,我们的控制器函数接受一个参数
$scope
,它是我们控制器的 依赖项。AngularJS 使用 依赖注入 来向我们提供此服务对象,从函数参数的名称推断正确的对象(还有一种替代语法也允许缩小)。我们现在向 HTML 模板添加一个
ng-controller
指令,以将其连接到我们的控制器:<code class="language-html"><div ng-app="ngOughts"> <p>同样,就像带有控制器名称的属性一样简单。有趣的事情发生在这里——嵌套在我们 body 标记内的元素现在可以访问 <code>$scope</code> 服务对象。然后,我们的 <code>ng-repeat</code> 属性将在 <code>BoardCtrl</code> 范围内查找 <code>board</code> 变量,所以让我们定义它:</p> <pre class="brush:php;toolbar:false"><code class="language-javascript">app.controller "BoardCtrl", ($scope) -></code>我们现在取得了一些进展。我们将
Board
注入到我们的控制器中,实例化它并使其在BoardCtrl
的范围内可用。让我们继续实现一个简单的
Board
类。<code class="language-html"><div ng-controller="BoardCtrl"> <table> <tr ng-repeat="row in board.grid"> ... </tr> </table> </div></code>添加工厂
然后,我们可以定义一个 工厂,它只返回
Board
类,允许将其注入到我们的控制器中。<code class="language-javascript">app.controller "BoardCtrl", ($scope, Board) -> $scope.board = new Board</code>可以在工厂函数内直接定义
Board
,甚至可以将Board
放到窗口对象上,但是在这里将其保持独立允许我们独立于 AngularJS 测试Board
,并鼓励可重用性。所以现在我们有一个空棋盘。令人兴奋的事情,对吧?让我们设置一下,以便单击一个单元格会在那里放置一个标记。
<code class="language-html"><table> <tr ng-repeat="row in board.grid"> <td ng-repeat="cell in row"> {{ cell.marker }} </td> </tr> </table></code>我们向每个
<td> 元素添加了一个 <code>ng-click
指令。当单击表格单元格时,我们将使用单击的单元格对象调用board
上的playCell
函数。填充Board
实现:<code class="language-html"><tr ng-repeat="row in board.grid"> <p></p> <h2>双向数据绑定</h2> <p>好的,所以现在我们已经更新了棋盘模型,我们需要更新视图,对吧?</p> <p>不!AngularJS 数据绑定是 <em>双向的</em>——它观察模型的更改并将它们传播回视图。同样,更新视图将更新相应的模型。我们的标记将在我们的 <code>Board</code> 内部网格中更新,并且 <code><td> 的内容将立即更改以反映这一点。 <p>这消除了您以前需要编写的许多脆弱的、依赖于选择器的样板代码。您可以专注于应用程序逻辑和行为,而不是管道。</p> <p>如果我们知道有人获胜就好了。让我们实现它。我们将在此处省略检查获胜条件的代码,但它存在于最终代码中。假设当我们找到获胜者时,我们会将获胜属性设置在构成获胜者的每个单元格上。</p> <p>然后我们可以将我们的 <code><td> 更改为如下所示: <pre class="brush:php;toolbar:false"><code class="language-html"><td ng-repeat="cell in row"> {{ cell.marker }} </td></code><code class="language-javascript">app = angular.module('ngOughts', ['ng'])</code>如果
winning
为真,ng-class
将将“winning”CSS 类应用于<td>,让我们设置一个令人愉悦的绿色背景来庆祝我们的胜利。你说再来一局?我们需要一个重置棋盘按钮: <pre class="brush:php;toolbar:false"><code class="language-html"><div ng-app="ngOughts"> <p>将其添加到我们的控制器中,我们将在单击按钮时调用 <code>reset</code>。棋盘标记将被清除,所有 CSS 类将被清除,我们准备再次开始——无需我们更新 DOM 元素。</p> <p>让我们真正炫耀我们的胜利:</p> <pre class="brush:php;toolbar:false"><code class="language-javascript">app.controller "BoardCtrl", ($scope) -></code></pre> <p><code>ng-show
指令允许我们在游戏获胜时有条件地显示<h1></h1>
元素,并且数据绑定允许我们插入获胜者的标记。简单而富有表现力。更易组合、更易测试的应用程序
值得注意的是,我们的大部分代码都处理的是普通的旧 JavaScript 代码。这是故意的——不扩展框架对象,只是编写和调用 JS 代码。这种方法有助于创建更易组合、更易测试的应用程序,这些应用程序感觉重量轻。我们的设计关注点通过 MVC 分离,但我们不需要编写大量代码来将它们连接在一起。
但是,AngularJS 也并非没有局限性。许多人抱怨官方文档和相对陡峭的学习曲线,有些人担心 SEO,还有些人只是讨厌使用非标准 HTML 属性和元素。
但是,这些问题都有解决方案,AngularJS 对 Web 开发的独特方法绝对值得花时间去探索。
您可以在 Plunkr 上查看最终代码的实际效果,或从 GitHub 下载它。
本文的评论已关闭。对 AngularJS 有疑问?为什么不在我们的论坛上提问呢?
关于 AngularJS 指令和数据绑定的常见问题
AngularJS 指令和组件有什么区别?
AngularJS 指令和组件都是 AngularJS 框架的强大功能。指令允许您创建可重用的自定义 HTML 元素和属性,而组件是一种使用更简单配置的特殊指令。组件适合构建基于组件的应用程序结构,这在当今前端开发中更为现代和广泛使用。但是,指令更灵活,可以直接操作 DOM,而组件则无法做到这一点。
AngularJS 中的数据绑定是如何工作的?
AngularJS 中的数据绑定是模型和视图组件之间数据的自动同步。AngularJS 实现数据绑定的方式允许您将模型视为应用程序中单一事实来源。视图始终是模型的投影。当模型更改时,视图会反映更改,反之亦然。
您可以解释单向数据绑定和双向数据绑定之间的区别吗?
单向数据绑定是数据从模型到视图或从视图到模型的简单流动。这意味着如果模型状态发生更改,视图将不会更新。另一方面,双向数据绑定意味着如果模型状态发生更改,视图将更新;如果视图发生更改(例如由于用户交互),模型状态将更新。这允许实时效果,这意味着更改(例如用户输入)将立即反映在模型状态中。
如何在 AngularJS 中创建自定义指令?
要在 AngularJS 中创建自定义指令,您需要使用
.directive
函数。您可以命名您的指令,然后创建一个工厂函数,该函数将保存所有指令选项。工厂函数使用依赖项(如果有)注入,然后它返回一个对象,该对象定义指令选项。AngularJS 指令中的隔离作用域是什么?
AngularJS 指令中的隔离作用域允许您为指令创建一个新的作用域。这意味着指令作用域中的任何更改都不会影响父作用域,反之亦然。当您想要创建可重用和模块化组件时,这非常有用。
如何在 AngularJS 指令中使用转录?
转录是 AngularJS 中的一个功能,允许您在指令内插入自定义内容。通过在指令定义对象中将
transclude
选项设置为true
,您可以在指令的模板中使用ng-transclude
指令来插入自定义内容。AngularJS 指令中的链接函数是什么?
链接函数用于 AngularJS 指令来操作 DOM 或添加事件侦听器。它在克隆模板后执行。此函数通常用于执行诸如设置 DOM 事件处理程序、监视模型属性的变化和更新 DOM 等任务。
如何在 AngularJS 指令中使用控制器函数?
控制器函数是一个 JavaScript 构造函数,用于增强 AngularJS 作用域。当控制器通过
ng-controller
指令附加到 DOM 时,AngularJS 将使用指定的控制器的构造函数实例化一个新的控制器对象。将创建一个新的子作用域,并作为可注入参数提供给控制器的构造函数作为$scope
。指令作用域选项中的“@”、“=”、“&”有什么区别?
这些符号用于将数据绑定到指令作用域。“@”用于字符串绑定,“=”用于双向模型绑定,“&”用于方法绑定。它们允许您隔离作用域,使您的指令更模块化和可重用。
如何测试我的 AngularJS 指令?
AngularJS 提供了一个名为
ngMock
的模块,允许您在单元测试中注入和模拟 AngularJS 服务。您可以使用它来测试您的指令。您还可以将 Jasmine 或 Mocha 等其他测试框架与ngMock
结合使用来编写和运行测试。
以上是Angularjs的详细内容。更多信息请关注PHP中文网其他相关文章!