周一到了,哈哈哈,周末在家看了会angular,今天都已经周三了,决定整理下所学所看,主要是指令中的compile和link的学习
先上个例子:
<!DOCTYPE html>
<html ng-app='MyApp'>
<meta charset="utf-8" />
<head>
<script type="text/javascript" src='https://code.angularjs.org/1.5.10/angular.min.js'></script>
<script type="text/javascript">
var app=angular.module('MyApp',[]);
app.controller('testC',function($scope){
$scope.title='angular学习';
$scope.text='whatever you want to say';
});
app.directive('repeater', function($document) {
return {
restrict: 'A',
compile: function(element, attrs) {
var template = element.children().clone();
for(var i=0; i<attrs.repeater - 1; i++) {
element.append(template.clone());
}
},
link: function(scope, elem, attrs) {
},
}
});
</script>
</head>
<body>
<div ng-controller='testC'>
<div>
<ul repeater=5>
<li>caicai</li>
</ul>
</div>
</div>
</body>
</html>
所有的指令的结构其实都大同小异,而我们平时见得大多数是只带link的,那么这个compile和Link到底是干嘛的呢
我们先来看看这个ng是怎样处理指令 的呢
当浏览所以器渲染一个页面时候,本质上是读取html标志,然后建立dom节点,生成dom树,当dom树创建完成后,会广播一个事件给我们,当我们在页面中使用scrrpt标签加载ng应用程序代码时候,ng监听上面的dom完成事件查找带有ng-app属性的元素。当找到这样的元素后,ng开始处理dom这个元素的起点,所以假如ng-app被添加到html元素中,则ng就会从html元素开始处理dom.从这个起点开始,ng开始递归查找所有子元素里面,已经定义好的符合程序的指令,ng怎么处理指令其实是依赖于它定义时的对象属性的,你可以自己定义一个compile或者link函数,或者用pre-link和post-link函数来代替link。简单而言按照字面理解就是编译的意思,像复制元素等都可以在compile中完成,link函数就是完成指令中中的一些与DOM的操作,如注册事件监听、监听模型、以及更新DOM 等。
compile函数
compile函数在link函数被执行之前用来做一些DOM改造,它接受下面参数
tElement-指令所在元素
attrs元素赋予的参数的标准化列表
app.directive('test', function() {
return {
compile: function(tElem,attrs) {
//do optional DOM transformation here
return {
pre: function(scope, iElem, iAttrs,controller){
},
post: function(scope, iElem, iAttrs,controller){
}
return function postLink(){}
};
}
};
});
举个例子:
<!DOCTYPE html>
<html ng-app='MyApp'>
<meta charset="utf-8" />
<head>
<script type="text/javascript" src='https://code.angularjs.org/1.5.10/angular.min.js'></script>
<script type="text/javascript">
var app=angular.module('MyApp',[]);
app.controller('testC',function($scope){
$scope.title='angular学习';
$scope.text='whatever you want to say';
});
app.directive('repeater', function($document) {
return {
restrict: 'A',
compile: function(element, attrs) {
var template = element.children().clone();
for(var i=0; i<attrs.repeater - 1; i++) {
element.append(template.clone());
}
},
link: function(scope, elem, attrs) {
},
}
});
</script>
</head>
<body>
<div ng-controller='testC'>
<div>
<ul repeater=5>
<li>caicai</li>
</ul>
</div>
</div>
</body>
</html>
输出结果:
看吧,这大概就是ng-repeat的实现,哈哈,可能你会奇怪了,哎,这个为什么没有pre postlink postlink呢,而是把link单独写在外面,其实compile中的postlink就是link函数,但是很多时候我们都不这么写,因为很多时候我们都不用compile函数,如果你想更深层次的研究pre post的话,可以继续看下去,我在后面写了这个,现在我们暂时放下compile,来看下link函数
link: function ($scope, $element, $attrs, ctrl) {
//获取teacher指令控制器,并调用其方法sayName()
$scope.teacherName = ctrl.sayName();
}
在link阶段要执行的函数,这个属性只有在compile属性没有设置时候才能生效
常用参数为scope element attr 分别为当前元素师的scope dom元素和元素上的属性,
举个例子:
<!DOCTYPE html>
<html ng-app='MyApp'>
<meta charset="utf-8" />
<head>
<script type="text/javascript" src='https://code.angularjs.org/1.5.10/angular.min.js'></script>
<script type="text/javascript">
var app=angular.module('MyApp',[]);
app.controller('testC',function($scope){
$scope.clickme=function(){
alert();
}
$scope.checkUsername = function() {
//send ajax to check on server
if ($scope.username === 'hellobug') {
$scope.usernameAlreadyExist = true;
}
}
$scope.title='angular学习';
$scope.text='whatever you want to say';
});
app.directive('ngSelf', function($document) {
return {
link: function(scope, element, attrs) {
element.bind('click', function(e){
scope.$apply(attrs.ngSelf);
});
}
}
})
</script>
</head>
<body>
<div ng-controller='testC'>
<div>
<button ng-self='clickme()'> click me</button>
</div>
</div>
</body>
</html>
当我们点击button时候,就会发现有alert弹出框
好了,我们综合下angular的指令到底是如何编译的:
前面已经说过了,当页面来到时候,浏览器API先将html转化为dom,然后通知大家dom加载完成,接着angular开始使用$compile服务遍历DOM元素,一旦所有的指令都被识别后,就执行他们的compile方法,compile方法返回一个link函数,被添加到稍后的link函数中,这被称为编译,如果一个指令需要被克隆很多次,compile只会在编译阶段被执行一次,复制这些模板,但是link函数会针对每个被复制的实例去执行,这也说明了为什么在compile函数中不能访问到scope对象,在编译阶段之后,就开始链接阶段,在这个阶段所有收集的link函数将被一一执行,指令创造出的模板会在正确的scope下被解析和处理,然后返回具有事件响应的真实的DOM节点
compile和link的使用时机
想在dom渲染前对其进行变形,并且不需要scope参数,返回值就是link的function
link
对特定元素注册事件
需要到scope参数来实现元素的一些行为
可能有时候我们还会见到这种情况:
下面是拷贝来的,真实性还未测试
使用controller的Directive
页面大致是:
<with-controller datasource="customers" add="addCustomer"></with-controller>
Directive方面:
(function(){
var withController = function(){
var template = '<button ng-click="addItem()">Add Item</button><ul>' + '<li ng-repeat="item in items">{{::item.name}}</li></ul>',
controller = ['$scope', function($scope){
init();
function init(){
$scope.items = angular.copy($scope.datasource);
}
$scope.addItem = function(){
var name = "customer new";
$scope.add()(name);
$scope.items.push({
name: name
});
}
}];
return {
restrict: 'EA',
scope: {
datasource: '=',
add:'&'
},
controller: controller,
template:template
}
};
angular.module('directiveModule')
.direcitve('withController', withController);
}());
可见,link和controller的相同点在于里面都可包含数据源和操作。不同点在于:link能控制渲染html元素的过程,而controller不能,controller的模版写死的,仅侧重于提供数据源和操作