(学习笔记)angular自定义指令

angularjs有两种创建自定义指令的方式:

1.module.directive(name,directiveFactory)

2.@see $compileProvider.directive()

var app=angular.module('myApp',[],function($compileProvider){
    	$compileProvider.directive('nameName',function(){
    	
    		//请不要使用ng为指令命名,这样可能会和angular内置指令冲突
    		//如果指令的名字为xxx-yyy,在设置指令的名字时应为xxxYyy驼峰式声明法
    	
        	return{
        		/**
        		自定义指令选项
        		**/
        		};
        	});
        });

指令定义选项:
priority
terminal
scope
controller
controllerAs
require
restrict
template
templateUrl
replace
transclude
compile
link

自定义选项详解:

restrict:如果忽略restrict,默认为A
如果打算支持ie8,请使用基于属性和样式的指令
E元素<name></name>
C样式<span class="name"></span>
A属性<span name></name>
M注释<!--directive:name-->
template
template:定义模板内容,这个内容会根据replace参数设置节点或替换节点内容.
例:template:'<div>123</div>'
replace:如果此配置为true则替换指令所在的元素,如果为false或者不指定,则把当前指令追加到所在元素内部
注意:最好设置replace属性为true,因为自定义标签在某些情况下不识别,即自定义的标签不符合H5规范
对于restrict为元素(E)在最终效果中多余的,所有replace通常设置为true

transclude
将将要被替换的标签内容加在替换后的标签内容之后
例:

template:'<div>替换数据 <span ng-transclude></span></div>',
transclude:true

templateUrl
templateUrl:加载模板所使用的URL
可以加载当前模板内对应的text/ng-template script id
例:

myApp.directive('customTag',function(){
	return{
		restrict:'ECMA',
		templateUrl:'scriptId',
		replace:true
}
});

注意:在使用chrome浏览器是,"同源政策"会阻止chrome从file://中加载模板,并显示一个"Access-Control-Allow-Origin"不允许源为null,可以把项目放到服务器加载,或者给Chrome设置一个标志,命令为:

chrome-allow-file-access-from-files

还有就是要注意与replace属性的冲突,要替换的内容必须有标签包含,即所选内容必须有H5标签包含(例:<div>content</div>, 不能:content),否则会报错

priority
pirority:设置指令在模板中的执行顺序,顺序是相对于元素上其他执行而言,默认为0,从大到小的顺序依次执行
设置优先级的情况较小,像ng-repeat,在遍历元素的过程中,需要angular先拷贝生成的模板元素,在应用其他指令,所以ng-repeat默认的priority是1000

terminal
terminal是否以当前指令的权重为结束界限,如果这个值设置为true,则节点中权重小于当前指令的其他指令不会被执行,相同权重会执行,通常与priority一起使用

compile
这里先说一下angular指令编译的三个阶段

angular指令编译的三个阶段
1.标准浏览器API转化
将html转化为dom,所以自定义的html标签必须符合html的格式
2.angular compile
搜索匹配directive,按照priority排序,并执行directive上的compile方法
3.angular link
执行directive上的link方法,进行scope绑定及事件绑定

compile
compile:function(tElement,tAttrs,transclude){}
compile函数用来对模板自身进行转化,仅仅在 编译阶段 运行一次
compiler中直接返回的函数是postllLink,表示link参数需要执行的函数,也可以放回一个对象里包含preLink和postLink

compile:function(tElement,tAttrs,transclude){
//编译阶段...
	return{
		postLink(scope,iElement,iAttrs,controller){
		//编译阶段之后,指令连接到子元素之前
		},
		preLink(scope,iElement,iAttrs,controller){
		//表示在所有子元素都连接之后
		}
	};
}

当定义compile参数时将无视link参数,因为compile返回的就是该指令需要执行的link函数

link
link(scope,iElement,iAttrs,controller)
link参数代表的是compile返回的postLink
preLink表示在编译阶段之后指令连接到子元素之前运行
postLink表示会在所有子元素指令都连接好之后才运行
link函数负责在模型和视图之间进行动态关联,对于每个指令的每个实例,link函数都会执行一次

controller
controller他会暴露一个API,利用这个API可以在多个指令之间通过依赖注入进行通信

 controller($scope,$element,$attrs,$transclude)

controllerAs
controllerAs的作用只是是给controller起个别名,方便使用

require
require可以将其他指令传递给自己
directiveName通过驼峰法的命名指令指定了控制器应该带有那一条指令,默认会从同一个元素上的指令
^directiveName在父级查找指令
?directiveName表示指令时可选的,如果找不到,不需要抛出异常

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title></title>
</head>
<body>
	<div ng-app='myApp' ng-controller="myCtrl">
		<div book-list></div>
	</div>

</body>
<script src="https://cdn.staticfile.org/angular.js/1.4.6/angular.min.js"></script>
<script type="text/javascript">
	var myApp=angular.module('myApp',[]);

	myApp.directive('bookList',function(){
		return{
			restrict:'ECAM',
			template:'<div><ul><li ng-repeat="book in books">{{book.name}}</li></ul><book-add></book-add></div>',
			replace:true,
			controller:function($scope){
				
				$scope.books=[
					{
						name:'angularjs'
					},
					{
						name:'javascript'
					},
					{
						name:'html'
					}
				];	
				this.addBook=function(){
					$scope.$apply(function(){
						$scope.books.push({name:'css'});
					});
						
					};	

			},
			controllerAs:'bookListController'
		}
	});

	myApp.directive('bookAdd',function(){
		return{
			restrict:'ECAM',
			template:'<button>添加</button>',
			replace:true,
			require:'^bookList',
			link:function(scope,iElement,iAttrs,bookListController){
				iElement.on('click',bookListController.addBook);
			}
		};
	});

	myApp.controller('myCtrl',function($scope){
			//...

	});
</script>
</html>

scope
scope:为当前指令创建一个新的作用域,而不是使之继承父作用域
scope有三中参量
1.false 继承父元素作用域(默认)
2.true 创建一个新的作用域,但可以继承父作用域
3.object 独立的作用域
object:参数
&:作用域把父作用域的属性包装成一个函数.从而以函数的方式读写父作用域的属性
=:作用域的属性与父作用域的属性进行双向绑定,任何一方的修改均影响到对方
@:只能读取父作用域的值单项绑定
例:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title></title>
</head>
<body>
	<div ng-app='myApp' ng-controller='firstController'>
		{{books}}

		<!--此books代表父控制器的books,传给了afnc---而afnc传给了a---a在传给了自定义指令的$scope.books-->
		<book-list afnc="books" parent-books='books' parent-title="{{title}}"></book-list>
		
	</div>
</body>
<script src="https://cdn.staticfile.org/angular.js/1.4.6/angular.min.js"></script>
<script type="text/javascript">
	var myApp=angular.module('myApp',[])
	.directive('bookList',function(){
		return{
			restrict:'ECAM',
			template:'<ul><li ng-repeat="book in books">{{book.name}}</li></ul>',
			replace:true,
			controller:function($scope){
				console.log($scope);


				//要用使用函数的方法去使用此属性
				$scope.books=$scope.a();
				//
				//$scope.books=$scope.b
				//
				//$scope.title=$scope.c;
				//console.log($scope.title)


			},

			/*
			*true:创建一个新的作用域,但可以继承父作用域
			false:使用父元素作用域
			对象:也会创建一个有继承链的作用域,默认无法享受继承的作用
			对象参数
			&作用域把副作用域的属性包装成一个函数,从而以函数的方式读写父作用域的属性	()
			=:作用域与父作用域的属性进行双向绑定,及一方修改,另一方会改动
			@:自能读取父元素的值进行单向绑定,只能绑定非引用类型的,不能绑定引用类型的	{{}}
			*/
			//当scope为对象时为一个独立的作用域
			scope:{
				//把父元素的books封装成一个a函数
				a:'&afnc'
				//双向绑定
				//b:'=parentBooks'
				//单向绑定
				//c:'@parentTitle'

			}
		}
	})

	.controller('firstController',function($scope){
			console.log($scope);
			$scope.books=[
				{
						name:'angularjs'
					},
					{
						name:'javascript'
					},
					{
						name:'html'
					}
			];
			$scope.title="标题"
		});
</script>
</html>

猜你喜欢

转载自blog.csdn.net/qq_44858021/article/details/94758856
今日推荐