带你走近AngularJS - 创建自定义指令

简介:

为什么使用AngularJS 指令?

使用过 AngularJS 的朋友应该最感兴趣的是它的指令。现今市场上的前端框架也只有AngularJS 拥有自定义指令的功能,并且AngularJS 是目前唯一提供Web应用可复用能力的框架。

目前有很多JavaScript 产品提供插件给Web开发人员。例如, Bootstrap 就是当前比较流行的提供样式和JavaScript插件的前端开发工具包。但是开发人员在使用Booostrap中的插件时, 必须切换到JavaScript 模式来写 jQuery 代码来激活插件虽然 jQuery 代码写起来十分简单,但是必须和HTML进行同步,这是一个单调乏味且容易出错的过程。

AngularJS主页展示了一个简单的例子,用于实现Bootstrap中的 Tab功能,可以在页面中轻松添加 Tab 功能,并且使用方法和 ul 标签一样简单。HTML代码如下:

1
2
3
4
5
6
7
8
9
10
11
< body  ng-app = "components" >
   < h3 >BootStrap Tab Component</ h3 >
   < tabs >
     < pane  title = "First Tab" >
       < div >This is the content of the first tab.</ div >
     </ pane >
     < pane  title = "Second Tab" >
       < div >This is the content of the second tab.</ div >
     </ pane >
   </ tabs >
</ body >


JavaScript代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
angular.module( 'components' , []).
   directive( 'tabs' function () {
     return  {
       restrict:  'E' ,
       transclude:  true ,
       scope: {},
       controller: [  "$scope" function ($scope) {
         var  panes = $scope.panes = [];
                                                                                                                                                                                                                                                                     
         $scope.select =  function (pane) {
           angular.forEach(panes,  function (pane) {
             pane.selected =  false ;
           });
           pane.selected =  true ;
         }
                                                                                                                                                                                                                                                                     
         this .addPane =  function (pane) {
           if  (panes.length == 0) $scope.select(pane);
           panes.push(pane);
         }
       }],
       template:
         '<div class="tabbable">'  +
           '<ul class="nav nav-tabs">'  +
             '<li ng-repeat="pane in panes" ng-class="{active:pane.selected}">' +
               '<a href="" ng-click="select(pane)">`pane`.`title`</a>'  +
             '</li>'  +
           '</ul>'  +
           '<div class="tab-content" ng-transclude></div>'  +
         '</div>' ,
       replace:  true
     };
   }).
   directive( 'pane' function () {
     return  {
       require:  '^tabs' ,
       restrict:  'E' ,
       transclude:  true ,
       scope: { title:  '@'  },
       link:  function (scope, element, attrs, tabsCtrl) {
         tabsCtrl.addPane(scope);
       },
       template:
         '<div class="tab-pane" ng-class="{active: selected}" ng-transclude>'  +
         '</div>' ,
       replace:  true
     };
   })

image

正如你所见,除了拥有用于实现指令的 <tabs> 和<pane> 标签,页面和常规HTML页面没有什么区别。HTML开发人员无需编写任何代码。当然,总需要有第一个吃螃蟹的人,创建指令共享使用,但是目前Tabs指令已经很常见了,可以在任何地方复用(如BootStrap,、jQueryUIWijmo, 和一些知名的前端插件集)。

由于指令的易用和易编写,许多用户已经开始使用AngularJS编写指令了。例如, AngularJS 开发组已经基于AngularJS实现了一系列指令-UI Bootstrap 来代替Bootstrap; 知名ComponentOne 控件厂商也在AngularJS 基础上创建了Wijmo ;我们也可以在GitHub上找到一些公共指令资料库:jQueryUI widgets

拥有了 AngularJS,是不是觉得自己已经站在了巨人的肩膀上了?但是不要高兴的太早,如果已经有了这么多的指令供我们使用,那我们为什么还要学习AngularJS ,为什么还要学习自定义指令呢?

举个简单的例子,也许你有特殊的需求:假设你在一家财务公司工作,你需要创建一张财务表单,它需要以表格的形式展示数据、拥有绑定、编辑、校验并且同步数据更新到服务器的功能。表单插件很常见但是能够满足这些具体需求的不得而知了,所以你必须根据实际业务需求来创建自定义指令。

1
2
3
4
5
6
7
< body  ng-app = "abcFinance" >
   < h3 >Offshore Investment Summary</ h3 >
   < abc-investment-form
     customer = "currentCustomer"
     country = "currentCountry" >
   </ abc-investment-form  data>
</ body >

这就是本篇文章的目的,接下来我们会讨论如何创建 AngularJS指令。


创建自定义AngularJS 指令

文章开头的自定义指令十分的简单。它仅仅实现了同步的功能。一般指令是包含更多元素的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//创建指令模块 (或者检索现有模块)
var  m = angular.module( "myApp" );
// 创建"my-dir"指令
myApp.directive( "myDir" function () {
   return  {
     restrict:  "E" ,         // 指令是一个元素 (并非属性)
     scope: {               // 设置指令对于的scope
       name:  "@" ,           // name 值传递 (字符串,单向绑定)
       amount:  "=" ,         // amount 引用传递(双向绑定)
       save:  "&"            // 保存操作
     },
     template:              // 替换HTML (使用scope中的变量)
       "<div>"  +
       "  `name`: <input ng-model='amount' />"  +
       "  <button ng-click='save()'>Save</button>"  +
       "</div>" ,
     replace:  true ,         // 使用模板替换原始标记
     transclude:  false ,     // 不复制原始HTML内容
     controller: [  "$scope" function  ($scope) { …  }],
     link:  function  (scope, element, attrs, controller) {…}
   }
});

效果如下:

image

注意这个自定义指令遵循一种格式:以"my" 为前缀,类似于命名空间,因此如果你在应用中引用了多个模块指令,你可以通过前缀很容易的判断出它是在哪定义的。这不是硬性要求,但是这样做可以带来很多便利。

指令的构造函数会返回带有属性的JavaScript 对象。这些内容在AngularJS 主页中都有清晰说明。以下是我对一些属性的理解:

  1. restrict: 说明指令在HTML中的应用形式,备选项有"A"、"E" 和 "C", "M" ,分别代表 attribute、element、class和comment(默认值为"A")。我们将更多的关注attributes-如何创建UI元素。

  2. scope: 创建指令的作用范围,scope在指令中作为属性标签传递。Scope 是创建可以复用指令的必要条件,每个指令(不论是处于嵌套指令的哪一级)都有其唯一的作用域,它不依赖于父scope。scope 对象定义names 和types 变量。上面的例子即创建了3个scope变量。

  • name: "@" (值传递,单向绑定): "@"符号表示变量是值传递。指令会检索从父级scope中传递而来字符串中的值。指令可以使用该值但无法修改,是最常用的变量。

  • amount: "=" (引用,双向绑定): "="符号表示变量是引用传递。指令检索主Scope中的引用取值。值可以是任意类型的,包括复合对象和数组。指令可以更改父级Scope中的值,所以当指令需要修改父级Scope中的值时我们就需要使用这种类型。

  • save: "&" (表达式) : “&”符号表示变量是在父级Scope中启作用的表达式。它允许指令实现比修改值更高级的操作。

  1. template: 替代原始模板中的标记的字符串。替换功能将替换所有旧元素为新值。注意template是如何使用Scope中定义的变量的。这允许你无需写任何额外的代码即可创建macro-style 风格指令。replace: 说明是否替换原始标记中的值或是追加原始标记中的值。默认值是false,这时原始标记将被保留。

  2. transclude: 说明自定义指令是否复制原始标记中的内容。例如,之前展示的“tab”指令设置了transclude 为 true,因为tab 元素包含其他HTML 元素。 "dateInput" 指令则需要在初始化时为空,所以需要设置transclude 为false。

  3. link: 该方法在指令中扮演着重要的角色。它负责执行DOM 操作和注册事件监听器等。link 方法包含以下参数:

  • scope: 指令Scope的引用。scope 变量在初始化时是不被定义的,link 方法会注册监视器监视值变化事件。

  • element: 包含指令的DOM元素的引用, link 方法一般通过jQuery 操作实例(如果没有加载jQuery,还可以使用Angular's jqLite )。

  • controller: 在有嵌套指令的情况下使用。这个参数作用在于把子指令的引用提供给父指令,允许指令之间进行交互, tab 指令就是使用该参数较典型的例子:http://jsfiddle.net/powertoolsteam/GBE7N/1/

注意,当调用link 方法时, 通过值传递("@")的scope 变量将不会被初始化,它们将会在指令的生命周期中另一个时间点进行初始化,如果你需要监听这个事件,可以使用scope.$watch 方法。 
好了,以上即为自定义指令需要用到基本知识描述。如果你仍然不熟悉指令,最好的方法就是动手实现几个小例子,可以在fiddle中进行实践:http://jsfiddle.net/powertoolsteam/Tk92U/



本文转自 powertoolsteam 51CTO博客,原文链接:http://blog.51cto.com/powertoolsteam/1412187,如需转载请自行联系原作者

相关文章
|
6月前
|
JavaScript
AngularJS中的自定义指令:创建与使用技术详解
【4月更文挑战第27天】本文详细介绍了AngularJS中自定义指令的创建与使用。通过定义指令工厂函数并注册到模块中,可以创建自定义指令,如示例中的`myCustomDirective`。指令的属性(如`restrict`、`template`、`replace`)和方法(如`link`、`scope`)可定制其行为。在HTML中使用`restrict`指定的方式(如元素、属性等)来插入指令。遵循命名规范,避免直接DOM操作,使用隔离作用域和关注重用性与扩展性,能有效提升代码质量。自定义指令是AngularJS强大功能之一,有助于实现复杂DOM操作和组件复用。
|
6月前
|
缓存 前端开发 UED
AngularJS的表单验证:深度探索与实践
【4月更文挑战第28天】本文深入探讨了AngularJS的表单验证,涉及基础用法、自定义规则和性能优化。AngularJS通过表单控制器和指令实现验证,ngModelController处理逻辑并更新错误状态。自定义验证器函数可扩展业务逻辑,性能问题可通过减少无效验证、异步处理和缓存解决。关注用户体验,提供清晰错误提示和一致验证规则至关重要。AngularJS的表单验证功能强大,适配复杂需求,助力构建高效、易用的验证系统。
|
6月前
|
前端开发 JavaScript API
AngularJS的动画系统:深入探索与实践
【4月更文挑战第28天】本文深入探讨AngularJS的动画系统,基于CSS3和JavaScript实现视图、元素的动画效果。通过ngAnimate模块管理动画,使用CSS类定义样式和行为,结合ng-enter等指令触发效果。支持列表和路由动画,但应注意性能优化,如减少不必要的操作、利用硬件加速及异步加载。良好的动画系统应具有一致性和可预测性,提升用户体验和交互性。
|
Web App开发 前端开发 JavaScript
|
Web App开发 JavaScript 前端开发