文档章节

AngularJS之动态菜单操作指令

w-rain
 w-rain
发布于 2017/04/24 15:47
字数 1747
阅读 416
收藏 12
点赞 0
评论 0

前言     

    在我们创建一个angularJS应用的时候,菜单往往往是不可或缺的元素之一。也许在我们静态菜单的时候不会发现在指令中操作菜单收缩、折叠展开没有任何问题,因为我们在操作之前,页面元素渲染已经完成,所以在指令里面通过element查找目标元素可以成功。但是一旦我们的菜单的数据不是静态而是通过后台接口加载动态数据渲染,我们会发现本来在静态写好的指令操作,在转变为动态数据加载之后,怎么也没法查找到想要的目标元素。

    遇到如此问题,开始觉得好奇葩的,当然这也是吐槽一下,还是得好好解决问题的,痛定失痛,决心好好理清思路,分析一下问题原因。首先我们先了解一下AngularJS的生命周期。

AngularJS的生命周期

    在AngularJS应用启动前,它们会以HTML文本的形式保存在文本编辑器中。应用启动后会进行编译和链接,作用域会同HTML进行绑定,应用可以对用户在HTML中进行的操作进行实时响应。AngularJS的生命周期主要有两个主要阶段:一个是编译阶段,一个是链接阶段。

AngularJS生命周期-编译阶段

    在编译阶段,AngularJS会遍历整个HTML文档并根据JavaScript中的指令定义来处理页面上声明的指令。每一个指令模板中可能有另一个指令,另一个指令也有可能会有自己的模板。AngularJS调用HTML文档根部的指令时,会遍历其中所有的模板,模板中可能含有模板的指令。如果一个元素已经有一个含有模板的指令,永远不要对其用另一个指令进行修饰,只有最高优先级的指令中的模板会被编译。

    一旦对指令和其中的子模板进行遍历或编译,编译后的模板会返回一个叫做模板函数的函数。在这个时候的DOM树还没有进行数据绑定,此时对DOM树操作只会有很少的性能开销,ng-repeat和ng-transclude等内置指令会在这个时候对还未进行数据绑定的DOM进行操作。比如ng-repeat,它会遍历指定的数组或对象,在数据绑定之前构建对应的DOM结构,然后将新的DOM(编译后的DOM)传递给指令生命周期中的下一阶段,链接阶段。一个指令的DOM一旦编译完成,就可以立即通过编译函数对其进行访问,编译函数的签名包含有访问指令声明所在的元素(tElements)及该元素对其他属性(tAttrs)的方法。

    compile返回对象或函数,compile()函数负责对模板DOM进行转换,link()函数负责将作用域和DOM进行转换。

//...
compile: function(tEle,tAttrs,transcludeFn){
    var tplEl = angular.element('<div>' +'<h2></h2>'+'</div>');
    var h2 = tplEl.find('h2');
    h2.attr('type',tAttrs.type);
    h2.attr('ng-model',tAttrs.ngModel);
    h2.val('hello');
    tEle.replaceWith(tplEl);
    return function(scope, ele, attrs){
     //连接函数



    };
}

//...

 

AngularJS生命周期-链接阶段

    link函数创建可以操作DOM的指令,链接函数是可选的。定义了编译函数,返回链接函数,当两个函数都定义了,编译函数会重载链接函数。


//下面2种定义指令的放松在功能上是完全一样的

angular.module('myApp',[])
.directive('myDirective', function (){
	return {
		pre: function (tElement, tAttrs, transclude){
			//在子元素被链接之前执行,之后调用‘link’函数无法定位链接的元素
			
		},
		post: function (scope, iElement, iAttrs, controllers){
            //在子元素被链接之后执行

		}
	}
});


angular.module('myApp',[])
.directive('myDirective', function (){
	return {
		link: function (scope, ele, attrs){
		   return {
		      pre: function (tElement, tAttrs, transclude){
			   	//在子元素被链接之前执行,之后调用‘link’函数无法定位链接的元素

		      },
		      post: function (scope, iElement, iAttrs, controllers){
            	//在子元素被链接之后执行

			  }
		   }
		}
	}
});

    当定义了编译函数来取代链接函数时,链接函数使我们能提供给返回对象的第二个方法,也就是postLink函数。链接函数会在模板编译并同作用域进行链接后被调用,它负责设置事件监听器,监听数据变化和实时的操作DOM。

//链接函数签名
link: function(scope, element, attrs){
	//操作DOM
}
//含require选项, require someContainer
link: function(scope, element, attrs, someContainer){
   //在这里操作DOM,可以访问require指定的控制器
}
  • scope--指令用来在其内部注册监听器的作用域;
  • element--参数代表实例元素,指使用此指令的元素;
  • atrrs--代表实例属性,是一个由定义在元素上的属性组成的标准化列表,可以在所有指令的链接函数间共享,会以javascript对象的形式进行传递;
  • controller 参数指向require选项定义的控制器。没有设置require选项,controller的参数为undefined;

    控制器在所有的指令间共享,因此指令可以将控制器当作通信通道(公共API),如果设置多个require,这个参数是一个控制器实例组成的数组,而不是一个单独的控制器。

问题剖析

    在通过对AngularJS生命周期的理解,我们可以清晰地认识到动态菜单为什么绑定在链接阶段上的DOM操作没有成功,由于ng-repeat的原因,我对DOM树操作没找到DOM元素。因为在封装成一个菜单指令组件的时候,我内部的菜单数据加载使用ng-repeat实现,所以只有在这个时候才能在ng-repeat内部绑定对DOM树的操作。

    最初的写法:

//html 
<menu-bar>
`````
<div ng-repeat="ml in menuLists">
	``````
	<div ng-repeat="mls in ml.secondLists">
		``````
		<div ng-repeat="mlt in mls.thirdLists">
		``````
		</div>
		``````
	</div>
	``````
</div>
``````
</menu-bar>

//directive
angular.module('',[]).directive('menuBar',function (){

	return {
	 restrict: 'E',
	 replace: true,
	 link: function (scope, element, attr){
	 //操作菜单的逻辑代码
	 }
	}

});

    这种写法,在link里面操作菜单逻辑的代码没有被触发,尼玛,angularjs的检测机制也没用,因为ng-repeat的原因导致DOM操作事件没有被挂载到DOM上,所以想操作菜单不可能成功。但是,如果ng-repeat的内容是静态存在的,link函数里面的操作是可以实现的。

    修改后的写法:

//html 
<div ng-repeat="ml in menuLists">
	``````
	<div ng-repeat="mls in ml.secondLists">
		``````
		<menu-bar>
			``````
			<div ng-repeat="mlt in mls.thirdLists">
				``````
				<menu-bar>
					``````
				</menu-bar>
				``````
			</div>
			``````
		</menu-bar>
		``````
	</div>
	``````
</div>

//directive
angular.module('',[]).directive('menuBar',function (){

	return {
	 restrict: 'E',
	 replace: true,
	 link: function (scope, element, attr){
	 //操作菜单的逻辑代码
	 }
	}

});

    修改之后我们将我们操作动态加载的DOM结构的指令放入ng-repeat中,此时逻辑正常执行,在link函数中能打印出DOM结构。

 

参考资料

【美】Ari Lerner 著《AngularJS 权威教程》

 

转载时请注明:来自w-rain的个人博客

© 著作权归作者所有

共有 人打赏支持
w-rain
粉丝 27
博文 52
码字总数 43952
作品 0
成都
程序员
AngularJS应用开发思维之1:声明式界面

这篇博客之前承接上一篇:http://www.cnblogs.com/xuema/p/4335180.html 重写示例:模板、指令和视图 AngularJS最显著的特点是用静态的HTML文档,就可以生成具有动态行为的页面。 还是前面的...

笔阁
2015/03/16
0
0
【前端】—聊聊我认识的Angular

前言 最近接触的项目前端用到了Angular框架,之前略有耳闻,从vue换到Angular,感觉东西差不多,还是要系统学习的,先来了解下。 正文 1、Angular 的发展 AngularJS 是一款来自Google的前端J...

zt15732625878
05/19
0
0
ngular2 VS Angular4 深度对比:特性、性能

在Web应用开发领域,Angular被认为是最好的开源JavaScript框架之一。 Google的Angular团队已于3月23日发布了Angular4,而期待已久的Angular2版本则是之前版本的完全重构。 对于成熟的开发人员...

机器的心脏
06/02
0
0
Angular.js 相关记录

AngularJS作用域文档:http://docs.angularjs.org/api/ng.$rootScope.Scope ng-view 指令的角色是为当前路由把对应的视图模板载入到布局模板中。 AngularJS内置过滤器:http://code.angular...

彭博
2014/04/25
0
2
JavaScript MVW 框架 - AngularJS

Angular JS (Angular.JS) 是一组用来开发 Web 页面的框架、模板以及数据绑定和丰富 UI 组件。它支持整个开发进程,提供 Web 应用的架构,无需进行手工 DOM 操作。 AngularJS 很小,只有 60K,...

匿名
2011/01/20
0
44
5个示例带你学习AngularJS

本文由 伯乐在线 - 蝈蝈 翻译自 tutorialzine。欢迎加入技术翻译小组。转载请参见文章末尾处的要求。 直到现在,你或许已经听说过AngularJS了,一个改变你对web应用思考方式,由谷歌开发的令...

冬瓜1
2013/12/30
0
0
AngularJS 中文资料+工具+库+Demo 大搜集

中文学习资料: 中文资料且成系统的就这么多,优酷上有个中文视频。 http://www.cnblogs.com/lcllao/archive/2012/10/18/2728787.html 翻译的官方的Guide http://www.ituring.com.cn/miniboo...

liaolzy2
2015/05/31
0
0
Angular 6正式版发布,都有哪些新功能

在Angular 5发布半年之后,Angular 6在昨天正式发布,那么在这个版本有哪些新功能呢?新版本重点关注工具链以及工具链在 Angular 中的运行速度问题。除此之外,这次更新还包括框架包(@angu...

code_xzh
05/05
0
0
Angular 6.0正式版发布,都有哪些新功能

点击关注异步图书,置顶公众号 每天与你分享IT好书 技术干货 职场知识 在Angular 5发布半年之后,Angular 6在昨天正式发布,那么在这个版本有哪些新功能呢?新版本重点关注工具链以及工具链在...

异步社区
05/08
0
0
所谓的 Virtual DOM 到底是什么?

首发地址在知乎,由于个人精力有限,可能无法在此进行快速回应。 背景 最近写了一个 ng-vdom 的 POC,用于将 Virtual DOM 对象渲染为原生 Angular 内容。 当然,重要的事情要说三遍: 这是一...

TrotylYu
06/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

shell中的函数、shell中的数组、告警系统需求分析

shell中的函数 格式: 格式: function f_name() { command } 函数必须要放在最前面 示例1(用来打印参数) 示例2(用于定义加法) 示例3(用于显示IP) shell中的数组 shell中的数组1 定义数...

Zhouliang6
46分钟前
2
0
用 Scikit-Learn 和 Pandas 学习线性回归

      对于想深入了解线性回归的童鞋,这里给出一个完整的例子,详细学完这个例子,对用scikit-learn来运行线性回归,评估模型不会有什么问题了。 1. 获取数据,定义问题     没有...

wangxuwei
今天
1
0
MAC安装MAVEN

一:下载maven压缩包(Zip或tar可选),解压压缩包 二:打开终端输入:vim ~/.bash_profile(如果找不到该文件新建一个:touch ./bash_profile) 三:输入i 四:输入maven环境变量配置 MAVEN_HO...

WALK_MAN
今天
0
0
33.iptables备份与恢复 firewalld的9个zone以及操作 service的操作

10.19 iptables规则备份和恢复 10.20 firewalld的9个zone 10.21 firewalld关于zone的操作 10.22 firewalld关于service的操作 10.19 iptables规则备份和恢复: ~1. 保存和备份iptables规则 ~2...

王鑫linux
今天
2
0
大数据教程(2.11):keeperalived+nginx高可用集群搭建教程

上一章节博主为大家介绍了目前大型互联网项目的系统架构体系,相信大家应该注意到其中很重要的一块知识nginx技术,在本节博主将为大家分享nginx的相关技术以及配置过程。 一、nginx相关概念 ...

em_aaron
今天
1
0
Apache Directory Studio连接Weblogic内置LDAP

OBIEE默认使用Weblogic内置LDAP管理用户及组。 要整理已存在的用户及组,此前办法是导出安全数据,文本编辑器打开认证文件,使用正则表达式获取用户及组的信息。 后来想到直接用Apache Dire...

wffger
今天
2
0
HFS

FS,它是一种上传文件的软件。 专为个人用户所设计的 HTTP 档案系统 - Http File Server,如果您觉得架设 FTP Server 太麻烦,那么这个软件可以提供您更方便的档案传输系统,下载后无须安装,...

garkey
今天
1
0
Java IO类库之BufferedInputStream

一、BufferedInputStream介绍 /** * A <code>BufferedInputStream</code> adds * functionality to another input stream-namely, * the ability to buffer the input and to * sup......

老韭菜
今天
0
0
STM 32 窗口看门狗

http://bbs.elecfans.com/jishu_805708_1_1.html https://blog.csdn.net/a1985831055/article/details/77404131...

whoisliang
昨天
1
0
Dubbo解析(六)-服务调用

当dubbo消费方和提供方都发布和引用完成后,第四步就是消费方调用提供方。 还是以dubbo的DemoService举例 -- 提供方<dubbo:application name="demo-provider"/><dubbo:registry address="z...

青离
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部