div>
script >
div >
<script >
var app = angular.module('myApp' , []);
app.controller('myController' , function ($scope) {
});
app.directive("myDirective" , function () {
return {
templateUrl : "template.html" ,
transclude : true
};
});
script >
body >
3.什么是scope的父作用域
引用自定义指令的html页面的控制器所能控制的范围。下面代码的父作用域就是myController 所控制的范围
<body >
<div ng-app ="myApp" ng-controller ="myController" >
<my-directive > my-directive >
div >
<script >
var app = angular.module('myApp' , []);
app.controller('myController' , function ($scope) {
});
app.directive("myDirective" , function () {
return {
template : "自定义指令! "
};
});
script >
body >
4.scope属性的值是对象(object)时的用法
AngularJS内置指令的用法:ng-model=”obj”,通过obj这个变量双向绑定值,controller里变了,html页面也跟着变化。这说明,内置指令不仅可作为属性,还可动态改变值,这个要是不懂的,看看基础语法。如下代码:
<div ng-app ="myApp" ng-controller ="myController" >
要动态变化的内容: <input ng-model ="obj" >
div >
<script >
var app = angular.module('myApp' , []);
app.controller('myController' , function ($scope) {
$scope.obj = "这个字符串值会同步到html里" ;
});
script >
自定义指令当然也需要实现这种功能啦。scope属性为对象时,可为自定义指令指定一个可以绑定值的属性。这里还得说明一下的是,这个scope属性与自定义指令里link属性里的scope参数是一个变量。
<body >
<div ng-app ="myApp" ng-controller ="myController" >
<my-directive speak ="obj" > my-directive >
div >
<script >
var app = angular.module('myApp' , []);
app.controller('myController' , function ($scope) {
$scope.obj="父作用域" ;
});
app.directive("myDirective" , function () {
return {
template : "模板内容
" ,
scope:{
title:"=speak"
},
link: function postLink (scope, iElement, iAttrs) {
console.log(scope.title)
}
};
});
script >
body >
有了前面的一个示例,下面再来说说绑定策略 :即用符号前缀给自定义指令传值。它是一个键值对,键是在自定义指令中使用的,值里符号后面的字符串是html页面自定义指令的属性名;如果值里只有符号,则html页面自定义指令的属性名就是键名。
符号
说明
示例
@
值传递,单向绑定。html页面自定义指令里的val属性的值可传给link的scope使用。第一种写法——str : “@”,这种写法html页面的指令属性名为str
str : “@val”,属性名为val
=
双向绑定数据到指令的属性中,数据值可以是任意类型的。第一种写法:name : “=”,这种写法html页面的自定义指令属性名就是name
name : “=username”,属性名是username
&
使用父作用域中的一个函数,可以在指令中调用。第一种写法:getName:”&”,这种写法html页面的自定义指令属性名就是gegName
getName : “&getUserName”,属性名是getUserName
其余两种符号用法:
<body >
<div ng-app ="myApp" ng-controller ="myController" >
<my-directive title ="obj" str ="abcd" > 自定义指定令的内容555my-directive >
div >
<script >
var app = angular.module('myApp' , []);
app.controller('myController' , function ($scope) {
$scope.obj="父作用域" ;
});
app.directive("myDirective" , function () {
return {
template : "模板内容
" ,
scope:{
title:"=" ,
str:"@"
},
link: function postLink (scope, iElement, iAttrs) {
console.log(scope.str)
console.log(scope.title)
}
};
});
script >
body >
<body >
<div ng-app ="myApp" ng-controller ="myController" >
<my-directive fun ="test()" > my-directive >
div >
<script >
var app = angular.module('myApp' , []);
app.controller('myController' , function ($scope) {
$scope.test = function () {
console.log('自定义指令会调用该法,所以这句话会打印到控制台上' )
}
});
app.directive("myDirective" , function () {
return {
template : "模板内容
" ,
scope:{
fun:"&"
},
link: function postLink (scope, iElement, iAttrs) {
scope.fun();
}
};
});
script >
body >
5.controller属性
controller 属性用于提供对外的接口,即该自定义指令会被其他自定义指令调用。所谓的接口,就是this后的变量或方法。 controller可以使用的参数,作用域、节点、节点的属性、节点内容的迁移,这些都可以通过依赖注入被传进来,所以你可以根据需要只写要用的参数,有$scope,Z$element, $attrs, $transclude
。 调用该自定义指令的指令需要放在该指令之间。假定firstDirective指令是要被调用的自定义指令,expander是调用者指令。如下:
<first-directive >
<expander ng-repeat ="item in list" attribute ="list" > {
{
item.title }} : {
{
item.text }} expander >
first-directive >
既然firstDirective内部还有指令,则firstDirective必须配置transclude属性为true。代码如下:
app.directive('firstDirective' ,function () {
return {
template : '
' ,
replace : true ,
transclude : true ,
controller :function () {
this .getData = function (val) {
var data = 3 * val;
return data;
}
this .a = "abc" ;
}
}
});
调用其他指令的自定义指令必须配置require属性指定指令名。然后在link函数里就可注入要调用的指令。
app.directive('expander' ,function () {
return {
templateUrl : 'template.html' ,
replace : true ,
transclude : true ,
require : '^?firstDirective' ,
scope : {
title : '=attribute'
},
link : function (scope,element,attris,firstDirct) {
console.log(firstDirct.a)
console.log(firstDirct.getData(6 ))
}
};
});
6.link属性用法
link后的方法在指令中负责执行DOM 操作和注册事件监听器等。link函数有五个参数(scope,element,attrs,controller,linker)。link 方法的参数解释: scope : 它与自定义指令里的scope属性 是一个东西。它是指令scope的引用,所以可改名为sco等其他名字。scope 变量在初始化时是不被定义的,link 方法会注册监视器监视值变化事件。 element : 包含指令的DOM元素的引用, link 方法一般通过jQuery 操作实例(如果没有加载jQuery,还可以使用Angular’s jqLite )。 controller : 在有嵌套指令的情况下使用。这个参数作用在于把子指令的引用提供给父指令,允许指令之间进行交互,如前面的例子。 注意 :当调用link 方法时, 通过值传递(”@”)的scope 变量将不会被初始化,它们将会在指令的生命周期中另一个时间点进行初始化,如果你需要监听这个事件,可以使用scope.$watch 方法。
7.link与compile的区别
compile函数有三个参数(cElement,cAttrs,cLinker),使用compile函数可以在ng创建原始dom实例以及创建scope实例之前,改变原始的dom(template element);可以应用于当需要生成多个element实例但只有一个template element的情况,ng-repeat就是一个最好的例子。它就在是compile函数阶段改变原始的dom生成多个原始dom节点,然后每个又生成element实例。因为compile只会运行一次,所以当你需要生成多个element实例的时候是可以提高性能的。 link函数有五个参数(scope,element,attrs,ctrl,linker)。 link又分为pre-link和post-link,在代码里直接用pre和post表示,当我们直接使用link时,默认跟post一样。我在网上找了个例子来说明一下区别,代码如下:
<body >
<div ng-app ="myApp" ng-controller ="myController" >
<level-one >
<level-two >
<level-three > Hello level-three >
level-two >
level-one >
div >
<script >
var app = angular.module('myApp' , []);
app.controller('myController' , function ($scope) {
});
function createDirective (name) {
return function () {
return {
restrict: 'E' ,
compile: function (tElem, tAttrs) {
console.log(name + ': compile => ' + tElem.html());
return {
pre: function (scope, iElem, iAttrs) {
console.log(name + ': pre link => ' + iElem.html());
},
post: function (scope, iElem, iAttrs) {
console.log(name + ': post link => ' + iElem.html());
}
}
}
}
}
}
app.directive('levelOne' , createDirective('levelOne' ));
app.directive('levelTwo' , createDirective('levelTwo' ));
app.directive('levelThree' , createDirective('levelThree' ));
script >
body >
注意打印结果:
levelOne: compile =>
< level-two >
< level-three >
Hello
< /level-three >
< /level-two >
levelTwo: compile =>
< level-three >
Hello
< /level-three >
levelThree: compile =>
Hello
levelOne: pre link =>
< level-two >
< level-three >
Hello
< /level-three >
< /level-two >
levelTwo: pre link =>
< level-three >
Hello
< /level-three >
levelThree: pre link =>
Hello
levelThree: post link =>
Hello
levelTwo: post link =>
< level-three >
Hello
< /level-three >
levelOne: post link =>
< level-two >
< level-three >
Hello
< /level-three >
< /level-two >
分析打印结果 : 运行levelone指令中的compile函数,ng就会递归遍历它的dom节点,然后在level-two与level-three上面重复这些操作。所以会依次打印连续三个compile。 pre会在所有compile执行完后且在所有post之前执行。这样可以在执行post前执行一些其他代码,有些类似AOP。 由上面结果可知,post的执行顺序却是先levelthree最后levelone,即反向调用相关联的post-link函数。这么做的好处是,当我们运行levelone时,保证leveltwo与levelthree都已经执行过了,这样就会更安全。所以默认的link就是post。
一个我做过的分页例子
之所以展示这个代码,主要是给一些朋友看看真实的项目,,多余的东西删掉了,具体的注入这里就不在讲了。 html页面代码:
<div class ="wp-20" ng-controller ="AppStatisticController" ng-cloak >
<div class ="panel-footer" >
<s-pagination conf ="paginationConf" > s-pagination >
div >
div >
控制器代码:
"use strict" ;
define(["application-configuration" , "s-pagination" , "tableDataService" ], function (app) {
app.register.controller("AppStatisticController" , ["$scope" , "$rootScope" , "$stateParams" ,"$http" , "tableDataService" ,
function ($scope , $rootScope , $stateParams , $http , tableDataService) {
var getTableDataSuccess = function (result) {
if (result.c == 1 ) {
$scope .title = result.title;
$scope .lists = result.pageList;
$scope .total = result.data;
$scope .paginationConf.totalItems = result.total;
}else if (result.c == 2 ){
} else {
alert(result.i);
}
};
var getTableDataError = function (result) {
alert(result);
};
$scope .paginationConf = {
currentPage: 1 ,
itemsPerPage: 10 ,
pagesLength: 9 ,
search: false ,
onChange: function () {
var param = {
"pageNo" : this.currentPage,
"pageSize" : this.itemsPerPage,
"timeType" : $scope .formData.timeType,
"adStyle" :$scope .formData.adStyle,
};
param.appId = $stateParams .appId;
tableDataService.getTableData(
param,
"ims/appStat.do" ,
getTableDataSuccess,
getTableDataError
);
}
};
$scope .$watch ("formData" ,function (newValue,oldValue, scope) {
if (newValue.keywords == oldValue.keywords) {
$scope .paginationConf.search = true ;
}
}, true );
}]);
});
自定义指令代码: 也算是angularJS的分页插件
angular.module('s.pagination' , []).directive('sPagination' ,[function () {
return {
restrict: 'E' ,
template: '' +
' +
'« ' +
' +
'ng-click="changeCurrentPage(item)">' +
'{
{ item }} ' +
' ' +
'» ' +
'' +
'' +
'第 页 ' +
'每页 ' +
'/共{
{ conf.totalItems }} 条' +
'
' +
'暂无数据
' +
' ' ,
replace: true ,
scope: {
conf: '='
},
link: function (scope, element, attrs) {
scope.changeCurrentPage = function (item) {
if (item == '...' ){
return ;
}else {
scope.conf.currentPage = item;
}
};
scope.conf.pagesLength = parseInt (scope.conf.pagesLength) ? parseInt (scope.conf.pagesLength) : 5 ;
if (scope.conf.pagesLength % 2 === 0 ){
scope.conf.pagesLength = scope.conf.pagesLength -1 ;
}
if (!scope.conf.perPageOptions){
scope.conf.perPageOptions = [10 , 20 , 30 , 40 , 50 ];
}
function getPagination (newValue, oldValue) {
if (newValue[1 ] != oldValue[1 ] || newValue[2 ] != oldValue[2 ]) {
scope.conf.search = true ;
}
scope.conf.currentPage = parseInt (scope.conf.currentPage) ? parseInt (scope.conf.currentPage) : 1 ;
scope.conf.totalItems = parseInt (scope.conf.totalItems) ? parseInt (scope.conf.totalItems) : 0 ;
scope.conf.itemsPerPage = parseInt (scope.conf.itemsPerPage) ? parseInt (scope.conf.itemsPerPage) : 15 ;
scope.conf.numberOfPages = Math .ceil(scope.conf.totalItems/scope.conf.itemsPerPage);
if (scope.conf.currentPage < 1 ){
scope.conf.currentPage = 1 ;
}
if (scope.conf.numberOfPages > 0 && scope.conf.currentPage > scope.conf.numberOfPages){
scope.conf.currentPage = scope.conf.numberOfPages;
}
scope.jumpPageNum = scope.conf.currentPage;
var perPageOptionsLength = scope.conf.perPageOptions.length;
var perPageOptionsStatus;
for (var i = 0 ; i < perPageOptionsLength; i++){
if (scope.conf.perPageOptions[i] == scope.conf.itemsPerPage){
perPageOptionsStatus = true ;
}
}
if (!perPageOptionsStatus){
scope.conf.perPageOptions.push(scope.conf.itemsPerPage);
}
scope.conf.perPageOptions.sort(function (a, b) {
return a-b});
scope.pageList = [];
if (scope.conf.numberOfPages <= scope.conf.pagesLength){
for (i =1 ; i <= scope.conf.numberOfPages; i++){
scope.pageList.push(i);
}
}else {
var offset = (scope.conf.pagesLength - 1 )/2 ;
if (scope.conf.currentPage <= offset){
for (i =1 ; i <= offset +1 ; i++){
scope.pageList.push(i);
}
scope.pageList.push('...' );
scope.pageList.push(scope.conf.numberOfPages);
}else if (scope.conf.currentPage > scope.conf.numberOfPages - offset){
scope.pageList.push(1 );
scope.pageList.push('...' );
for (i = offset + 1 ; i >= 1 ; i--){
scope.pageList.push(scope.conf.numberOfPages - i);
}
scope.pageList.push(scope.conf.numberOfPages);
}else {
scope.pageList.push(1 );
scope.pageList.push('...' );
for (i = Math .ceil(offset/2 ) ; i >= 1 ; i--){
scope.pageList.push(scope.conf.currentPage - i);
}
scope.pageList.push(scope.conf.currentPage);
for (i = 1 ; i <= offset/2 ; i++){
scope.pageList.push(scope.conf.currentPage + i);
}
scope.pageList.push('...' );
scope.pageList.push(scope.conf.numberOfPages);
}
}
if (scope.conf.onChange){
if (scope.conf.search) {
scope.conf.onChange();
scope.conf.search = false ;
}
}
scope.$parent.conf = scope.conf;
}
scope.prevPage = function () {
if (scope.conf.currentPage > 1 ){
scope.conf.currentPage -= 1 ;
}
};
scope.nextPage = function () {
if (scope.conf.currentPage < scope.conf.numberOfPages){
scope.conf.currentPage += 1 ;
}
};
scope.jumpToPage = function () {
scope.jumpPageNum = scope.jumpPageNum.replace(/[^0-9]/g ,'' );
if (scope.jumpPageNum !== '' ){
scope.conf.currentPage = scope.jumpPageNum;
}
};
scope.$watch(function () {
if (!scope.conf.totalItems) {
scope.conf.totalItems = 0 ;
}
if (angular.isUndefined(scope.conf.search)) {
scope.conf.search = false ;
}
var newValue = [scope.conf.totalItems, scope.conf.currentPage, scope.conf.itemsPerPage, scope.conf.search];
return newValue;
}, getPagination, true );
}
};
}]);