前言
在我们创建一个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指定的控制器 }
控制器在所有的指令间共享,因此指令可以将控制器当作通信通道(公共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结构。
以上所述是小编给大家介绍的AngularJS动态菜单操作指令,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对小牛知识库网站的支持!
ActionSheet 操作菜单 平台差异说明 App H5 微信小程序 支付宝小程序 百度小程序 头条小程序 QQ小程序 √ √ √ √ √ √ √ 基本使用 通过list设置需要显示的菜单,该值为一个数组,元素为对象,对象至少要提供text属性,另外可选的有fontSize(字体大小),color(颜色),disabled(是否禁用,1.5.6引入), subText(描述信息,1.6.8引入
我想要的是:但是现在改变来了,我想要的是,我需要在我执行向右或向左滑动后显示一些图标。然后通过点击那些图标/按钮,我想执行操作。 问题:正如我告诉你的,问题是我已经实现了ItemTouchHelper,然后我如何执行我想要的(如上所述) 这怎么解决?我见过许多库,但它们都有局限性,也因为应用程序有很多事情要做,我们的应用程序中使用了RecycerView上的一些更多实现,所以我真的不想为了这个而冒
问题内容: 我正在尝试根据范围值使用不同的模板进行指令。 这是我到目前为止所做的,我不知道为什么它不起作用http://jsbin.com/mibeyotu/1/edit HTML元素: 指示: 问题答案: 1)您正在将内容作为属性传递到html中。试试这个: 代替: 2)指令的数据部分正在被编译,因此您应该使用其他东西。代替数据类型,例如datan-type。 链接在这里: http://jsb
问题内容: 尝试将指令添加到具有动态ID的输入时,链接方法未正确绑定到该对象。给定以下jsfiddle或html: 和js: 我在控制台调试器上看到的是,当链接被调用时,其ID实际上显示为“ datepicker-{{{id}}””而不是“ datepicker-7”。 有办法强迫这种情况发生吗?实施此方法的更好方法? 更新 :应该已经澄清。单击日期选择器会显示出来,但是单击日期不起作用。我收到错
不管用……。
实现带动画效果的下拉菜单。用户按下菜单按钮,出现下拉按钮,用户松开菜单按钮,下拉按钮收回。 [Code4App.com]