带你走近AngularJS - 体验指令实例
带你走近AngularJS系列:
------------------------------------------------------------------------------------------------
之前我们已经介绍了所有的AngularJS 基础知识,下面让我们通过实例来加深记忆,体验自定义指令的乐趣。
手风琴指令
我们展示的第一个例子是手风琴效果指令:
效果图如下:
在线实例地址:手风琴指令
不使用AngularJS的纯HTML源码如下:
<div class="accordion" id="accordion2">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse"
data-parent="#accordion2" href="#collapseOne">
Collapsible Group Item #1
</a>
</div>
<div id="collapseOne" class="accordion-body collapse in">
<div class="accordion-inner">
Anim pariatur cliche...
</div>
</div>
</div>
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse"
data-parent="#accordion2" href="#collapseTwo">
Collapsible Group Item #2
</a>
</div>
<div id="collapseTwo" class="accordion-body collapse">
<div class="accordion-inner">
Anim pariatur cliche...
</div>
</div>
</div>
</div>
以上纯 HTML源码也可以实现手风琴效果,但是它仅仅是一些标记,包含了大量的链接和id,不利于维护。
使用AngularJS自定义指令结合以下HTML源码同样可以得到预期效果:
<body ng-app="btst">
<h3>BootStrap手风琴指令</h3> <btst-accordion>
<btst-pane title="<b>基本功能</b>" category="{name:'test'}">
<div>AngularJS......</div>
</btst-pane>
<btst-pane title="<b>创建自定义指令</b>">
<div>使用过 AngularJS ......</div>
</btst-pane>
<btst-pane title="<b>体验实例</b>">
<div>之前我们已经介绍了所有的AngularJS......</div>
</btst-pane>
</btst-accordion>
</body>
这一版使用的HTML标记更少,看起来清晰且易维护。
下面,让我们看下指令写法。
首先,我们定义模块"btstAccordion" 指令:
var btst = angular.module("btst", []);
btst.directive("btstAccordion", function () {
return {
restrict: "E",
transclude: true,
replace: true,
scope: {},
template:
"<div class='accordion' ng-transclude></div>",
link: function (scope, element, attrs) { // 确保 accordion拥有id
var id = element.attr("id");
if (!id) {
id = "btst-acc" + scope.$id;
element.attr("id", id);
} // set data-parent and href attributes on accordion-toggle elements
var arr = element.find(".accordion-toggle");
for (var i = 0; i < arr.length; i++) {
$(arr[i]).attr("data-parent", "#" + id);
$(arr[i]).attr("href", "#" + id + "collapse" + i);
} // set collapse attribute on accordion-body elements
// and expand the first pane to start
arr = element.find(".accordion-body");
$(arr[0]).addClass("in"); // expand first pane
for (var i = 0; i < arr.length; i++) {
$(arr[i]).attr("id", id + "collapse" + i);
}
},
controller: function () {}
};
});
由于拥有内部HTML内容,所以设置指令的transclude 属性为true。模板使用ng-transclude 指令来声明对应的显示内容。由于模板中只有一个元素,所以没有设置其他选项。
代码中最有趣的部分是link 方法。它在参数element具有id时启作用,如果没有,会依据指令的 Scope自动创建ID。一旦元素拥有了ID值,方法将通过jQuery来选择具有"accordion-toggle"类的子元素并且设置它的 "data-parent" 和 "href" 属性。最后,通过寻找“accordion-body” 元素,并且设置"collapse" 属性。
指令同时声明了一个拥有空方法的controller 。声明controller 是必要的,因为Accordion会包含子元素,子元素将检测父元素的类型和controller 。
下一步需要定义手风琴选项卡的指令。
这一步比较容易,大多数操作将在这个模板中发生,但是它仅仅需要少量的代码:
btst.directive('btstPane', function () {
return {
require: "^btstAccordion",
restrict: "E",
transclude: true,
replace: true,
scope: {
title: "@"
},
template:
"<div class='accordion-group'>" +
" <div class='accordion-heading'>" +
" <a class='accordion-toggle' data-toggle='collapse'>{{title}}</a>" +
" </div>" +
"<div class='accordion-body collapse'>" +
" <div class='accordion-inner' ng-transclude></div>" +
" </div>" +
"</div>",
link: function (scope, element, attrs) {
scope.$watch("title", function () {
// NOTE: this requires jQuery (jQLite won't do html)
var hdr = element.find(".accordion-toggle");
hdr.html(scope.title);
});
}
};
});
require 属性值为"btstPane" ,所以该指令必须用于指令"btstAccordion"中。transclude 属性为true表明选项卡包含HTML标签。scope 下的 "title" 属性将会被实例所替代。
这个例子中的模板比较复杂。注意我们通过ng-transclude 指令来标记元素接收文本内容。
模板中"{{title}}" 属性将会显示标签名称。目前我们仅仅实现了纯文本显示,没有定义其样式。我们使用link 方法可以替换标题为HTML源码从而得到更丰富的样式。
就这样,我们完成了第一个具有实用价值的指令。它功能并不复杂但是足以展示一些AngularJS的重要知识点和技术细节:如何定义嵌套指令,如何生成唯一的元素ID,如何使用jQuery操作DOM以及如何使用$watch 方法监听scope变量的变化。
Google Maps 指令
下一个例子是创建Google地图的指令:
在我们创建指令之前,我们需要添加Google APIs 引用到页面中:
<!-- required to use Google maps --> <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?sensor=true"> </script>
接下来,我们创建指令:
var app = angular.module("app", []);
app.directive("appMap", function () {
return {
restrict: "E",
replace: true,
template: "<div></div>",
scope: {
center: "=", // Center point on the map
markers: "=", // Array of map markers
width: "@", // Map width in pixels.
height: "@", // Map height in pixels.
zoom: "@", // Zoom level (from 1 to 25).
mapTypeId: "@" // roadmap, satellite, hybrid, or terrain
},
center 属性进行了双向绑定。这个应用可以改变地图中心和交互地图(当用户通过鼠标按钮选择地图位置时)。同时,地图也会在用户通过滚动选择地图位置时通知应用更新当前显示位置。
markers 属性被定义为引用因为它是数组形式,把它序列化为字符串比较耗时。link 方法可以实现以下功能:
1. 初始化地图
2. 在用户视图变量更改时更新地图
3. 监听事件
以下是实现代码:
link: function (scope, element, attrs) {
var toResize, toCenter;
var map;
var currentMarkers; // listen to changes in scope variables and update the control
var arr = ["width", "height", "markers", "mapTypeId"];
for (var i = 0, cnt = arr.length; i < arr.length; i++) {
scope.$watch(arr[i], function () {
if (--cnt <= 0)
updateControl();
});
} // update zoom and center without re-creating the map
scope.$watch("zoom", function () {
if (map && scope.zoom)
map.setZoom(scope.zoom * 1);
});
scope.$watch("center", function () {
if (map && scope.center)
map.setCenter(getLocation(scope.center));
});
监测方法正如我们在文章开始时描述的,变量发生变化后,它将调用updateControl 方法。updateControl 方法实际上使用selected 选项创建了新的地图。
"zoom" 和 "center" 变量将被分别处理,因为我们不希望每次在用户选择或缩放地图时都重新创建地图。这两个方法检测地图是否重新创建还是仅仅是简单的更新。
以下是updateControl 方法的实现方法:
// update the control
function updateControl() { // get map options
var options = {
center: new google.maps.LatLng(40, -73),
zoom: 6,
mapTypeId: "roadmap"
};
if (scope.center) options.center = getLocation(scope.center);
if (scope.zoom) options.zoom = scope.zoom * 1;
if (scope.mapTypeId) options.mapTypeId = scope.mapTypeId;
// create the map and update the markers
map = new google.maps.Map(element[0], options);
updateMarkers(); // listen to changes in the center property and update the scope
google.maps.event.addListener(map, 'center_changed', function () {
if (toCenter) clearTimeout(toCenter);
toCenter = setTimeout(function () {
if (scope.center) {
if (map.center.lat() != scope.center.lat ||
map.center.lng() != scope.center.lon) {
scope.center = { lat: map.center.lat(), lon: map.center.lng() };
if (!scope.$$phase) scope.$apply("center");
}
}
}, 500);
}
updateControl 方法首先需要接收Scope设置相关参数,接着使用options 创建和初始化地图。这是创建JavaScript指令的常见模式。
创建地图之后,方法会在更新标记的同时添加检测事件,以便监视地图中心位置的变化。该事件会监测当前的地图中心是否和Scope中的相同。如果不同,即会更新scope,调用$apply 方法通知AngularJS属性已经更改。这种绑定方式为双向绑定。
updateMarkers 方法十分的简单,几乎和AngularJS分离,所以我们在这里就不介绍了。
除了这个地图指令特有的功能,这个例子还展示了:
1. 两个过滤器转换坐标为常规数字到地理位置,例如33°38'24"N, 85°49'2"W。
2. 一个地理编码器,转换成地址的地理位置(也是基于谷歌的API)。
3. 使用HTML5的地理定位服务来获取用户当前位置的方法。
Google地图 APIs 是极其丰富的。以下是一些资源入口:
Google地图APIs 文档: https://developers.google.com/maps/documentation/
Google许可条款:https://developers.google.com/maps/licensing
Wijmo Grid 指令
最后一个例子是可编辑的表格指令:
这里展示的图表插件是 Wijmo 前端插件套包中的一款插件 wijgrid 插件:
<wij-grid
data="data"
allow-editing="true"
after-cell-edit="cellEdited(e, args)" >
<wij-grid-column
binding="country" width="100" group="true">
</wij-grid-column>
<wij-grid-column
binding="product" width="140" >
</wij-grid-column>
<wij-grid-column
binding="amount" width="100" format="c2" aggregate="sum" >
</wij-grid-column>
</wij-grid>
"wij-grid" 指令定制表格的属性,"wij-grid-column" 指令定制特性表格列的属性。以上标记定义了一个拥有三列的可编辑表格,分别为:“country”, "product" 和 "amount"。并且,以country列分组并且计算每个分组的合计。
这个指令中最特别的一点是 “wij-grid”和“wij-grid-column”的连接。为了使这个连接起作用,父指令中定义了如下controller:
app.directive("wijGrid", [ "$rootScope", "wijUtil", function ($rootScope, wijUtil) {
return {
restrict: "E",
replace: true,
transclude: true,
template: "<table ng-transclude/>",
scope: {
data: "=", // List of items to bind to.
allowEditing: "@", // Whether user can edit the grid.
afterCellEdit: "&", // Event that fires after cell edits.
allowWrapping: "@", // Whether text should wrap within cells.
frozenColumns: "@" // Number of non-scrollable columns
},
controller: ["$scope", function ($scope) {
$scope.columns = [];
this.addColumn = function (column) {
$scope.columns.push(column);
}
}],
link: function (scope, element, attrs) {
// omitted for brevity, see full source here:
// http://jsfiddle.net/Wijmo/jmp47/
}
}
}]);
关于controller 方法使用前文中提到的数组语法声明,在这个例子中,controller定义了addColumn 方法,它将会被"wij-grid-column" 指令调用。父指令会通过特定标记来访问列。
以下是"wij-grid-column" 指令的使用方法:
app.directive("wijGridColumn", function () {
return {
require: "^wijGrid",
restrict: "E",
replace: true,
template: "<div></div>",
scope: {
binding: "@", // Property shown in this column.
header: "@", // Column header content.
format: "@", // Format used to display numeric values in this column.
width: "@", // Column width in pixels.
aggregate: "@", // Aggregate to display in group header rows.
group: "@", // Whether items should be grouped by the values in this column.
groupHeader: "@" // Text to display in the group header rows.
},
link: function (scope, element, attrs, wijGrid) {
wijGrid.addColumn(scope);
}
}
});
require 成员用于指定"wij-grid-column" 指令的父级指令"wij-grid"。link 方法接收父指令的引用 (controller) ,同时通过addColumn 方法传递自身的scope 给父指令。scope 包含了表格用于创建列的所有信息。
更多指令
链接为一些AngularJS 指令的在线实例: http://wijmo.gcpowertools.com.cn/demo/AngularExplorer/ ,你可以在例子的基础上进行练习。例子都是严格的安照本文中的描述制作的,所以你可以无障碍学习他们。
资源推荐:
1. AngularJS by Google AngularJS主页。
2. AngularJS Directives documentation AngularJS 指令官方帮助文档。
3. AngularJS directives and the computer science of JavaScript 比较实用的AngularJS指令说明文章。
4. Video Tutorial: AngularJS Fundamentals in 60-ish Minutes AngularJS 介绍视频。
5. About those directives AngularJS 研发人员发布的视频教程。
6. Egghead.io AngularJS 使用系列视频教程。
7. Wijmo AngularJS Samples AngularJS 在线实例。
相关阅读:
Wijmo已率先支持Angular4 & TypeScript 2.2
带你走近AngularJS - 体验指令实例的更多相关文章
- 带你走近AngularJS - 创建自定义指令
带你走近AngularJS系列: 带你走近AngularJS - 基本功能介绍 带你走近AngularJS - 体验指令实例 带你走近AngularJS - 创建自定义指令 ------------- ...
- 带你走近AngularJS - 创建自己定义指令
带你走近AngularJS系列: 带你走近AngularJS - 基本功能介绍 带你走近AngularJS - 体验指令实例 带你走近AngularJS - 创建自己定义指令 ------------ ...
- 带你走近AngularJS - 基本功能介绍
带你走近AngularJS系列: 带你走近AngularJS - 基本功能介绍 带你走近AngularJS - 体验指令实例 带你走近AngularJS - 创建自定义指令 ------------- ...
- 带你走近AngularJS 之创建自定义指令
带你走近AngularJS 之创建自定义指令 为什么使用AngularJS 指令? 使用过 AngularJS 的朋友应该最感兴趣的是它的指令.现今市场上的前端框架也只有AngularJS 拥有自定义 ...
- 接近带给你AngularJS - 经验说明示例
接近带给你AngularJS列: 带你走近AngularJS - 基本功能介绍 带你走近AngularJS - 体验指令实例 带你走近AngularJS - 创建自己定义指令 ------------ ...
- AngularJS之指令
紧接上篇博客“初探AngularJS” 一.前言 在AngularJS中指令尤为重要且内容庞多,固单独提炼出来,梳理一番.如有错误,请不吝讲解. 好了,言归正传,让我们一起走进Angular指令的世界 ...
- AngulaJS实战总结, 带你进入AngularJS世界(待续)
使用AngularJS 进行Hybrid App 开发已经有一年多时间了,这里做一个总结. 一.AngularJS 初始化加载流程 1.浏览器载入HTML,然后把它解析成DOM.2.浏览器载入ang ...
- 学习AngularJs:Directive指令用法(完整版)
这篇文章主要学习AngularJs:Directive指令用法,内容很全面,感兴趣的小伙伴们可以参考一下 本教程使用AngularJs版本:1.5.3 AngularJs GitHub: http ...
- AngularJs:Directive指令用法
摘自:http://www.jb51.net/article/83051.htm 摘要:Directive(指令)是AngularJ非常强大而有有用的功能之一.它就相当于为我们写了公共的自定义DOM元 ...
随机推荐
- js弹出公告
调用: $(document).ready(function(){ sAlert("公告","内容"); }); 方法 function sAlert(strT ...
- 一行css代码调试中学到的javascript知识,很有意思
现在到处都是JavaScript,每天都能知道点新东西.一旦你入了门,你总能从这里或是那里领悟到很多知识.今天我想分享Addy Osmani的一行代码 ,这行代码对于你调试你的CSS是很有用的.为了可 ...
- Fiddler 手机端证书安装No root certificate was found
测试过程中发现在浏览器中访问代理服务器及端口,不通,提示要安装证书. 点击证书安装时,提示错误: No root certificate was found,Have you enabled HTTP ...
- kettle(6.0)如何连接远程集群(CDH5.1)?
最近因为公司业务需要,刚刚接触了kettle.这不看不知道,一看才发现kettle的功能是在是太强大了,让我有种相见恨晚的感觉.由于主要是应用kettle与hadoop集群和hive连接进行数据处理. ...
- 将 project.json 项目转换为 Visual Studio 2015 解决方案
var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...
- 关于gridview里加按钮事件的总结
1. onrowcommand="GridView1_RowCommand1" 在gridview申明时的属性里要有,然后找到闪电,双击 还有要把那个按钮行模板化,就是箭头里面的t ...
- #include <stdarg.h>
名称描述相容 // 作用描述 va_start使va_list指向起始的参数 va_arg检索参数C89 va_end释放va_list va_copy拷贝va_list的内容 实例解析: #inc ...
- Linux内核--网络栈实现分析(四)--网络层之IP协议(上)
本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7514017 更多请看专栏,地址 ...
- 如何在Windows中编译Linux Unix的代码(采用cygwin)?
来源:http://www.cnblogs.com/rocky_yi/archive/2009/12/08/cygwin.html 作者:rocky_y 很多经典算法往往是用C++在linux下实 ...
- cocoapods安装以及使用,安装过程中ruby版本过低
cocoapods安装以及使用,安装过程中ruby版本过低 字数473 阅读103 评论1 喜欢2 1.打开终端 2.移除现有 Ruby 默认源 $ gem sources --remove http ...