业务中有时需要在异步获取数据并用ng-repeat遍历渲染完页面后执行某个操作,angular本身并没有提供监听ng-repeat渲染完成的指令,所以需要自己动手写。有经验的同学都应该知道,在ng-repeat模板实例内部会暴露出一些特殊属性$index/$first/$middle/$last/$odd/$even,$index会随着每次遍历(从0开始)递增,当遍历到最后一个时,$last的值为true,so,通过判断$last的值来监听ng-repeat的执行状态,怎么在遍历过程中拿到$last的值:自定义指令

小实例,我只写了最重要的部分

//要循环的数据
$scope.data = [
{
str: 'a'
},
{
str: 'b'
},
{
str: 'c'
}
]
//自定义指令repeatFinish
app.directive('repeatFinish',function(){
return {
link: function(scope,element,attr){
console.log(scope.$index)
if(scope.$last == true){
console.log('ng-repeat执行完毕')
}
}
}
})
<div id="box">
<span ng-repeat="item in data" repeat-finish>{{item.str}}</span>
</div>

打开控制台,会打印出0,1,2,当$index = 2点时候,$last值为true,ng-repeat渲染完毕

so easy!

当然指令最好是能够复用,在这个指令内写具体的业务逻辑不利于复用,可以通过给指令指定一个处理函数renderFinish

<div id="box">
<span ng-repeat="item in data" repeat-finish="renderFinish()">{{item.str}}</span>
</div>

再通过指令的attr参数获取这个处理函数

app.directive('repeatFinish',function(){
return {
link: function(scope,element,attr){
console.log(scope.$index)
if(scope.$last == true){
console.log('ng-repeat执行完毕')
scope.$eval( attr.repeatFinish )
}
}
}
})
//controller里对应的处理函数
$scope.renderFinish = function(){
console.log('渲染完之后的操作')
}

attr获取到的属性只是一个字符串表达式,$scope.$eval方法是专门执行AngularJS表达式的,通过它处理函数得以执行,这样,指令用在不同的地方,可传递不同的处理函数。

有些业务比较复杂,可能ng-repeat渲染完成之后,需要执行多个操作并且这多个操作有多个前端完成,需要用到angular的事件,在repeatFinish指令的link函数内触发一个事件,各位前端同学监听该事件完成各自的操作

app.directive('repeatFinish',function(){
return {
link: function(scope,element,attr){
console.log(scope.$index)
if(scope.$last == true){
console.log('ng-repeat执行完毕')
//向父控制器传递事件
scope.$emit('to-parent');
//向子控制器传递事件
scope.$broadcast('to-child');
}
}
}
})
//父控制器中监听事件
$scope.$on('to-parent',function(){
//父控制器执行操作
}) //子控制器中监听事件
$scope.$on('to-child',function(){
//子控制器执行操作
})

如何在当前控制器下监听到该事件呢?angular没有向当前控制器传递事件的方法,可以先向父(子)控制器传递事件,父(子)控制器监听到事件后反过来向子(父)控制器传递事件。

补充:IE8可以直接在元素上用指令ng-if="$last && renderFinish()",当然IE8+也可以这样用

一句话总结:指令是angular的核心功能之一,用好了事半功倍,监听ng-repeat执行状态仅仅是它功能的冰山一角吧

补充2:然后我在使用的时候发现一个问题。这个问题依然是延时回调引起的,这不同于$http的异步问题,它不是异步,仅仅是延时问题。

    我实用fbug断点调试发现,原来所谓的渲染完毕,其实并没有真正把数据填上,而是dom的渲染完毕,数据要等所有的dom渲染完毕之后对号入座。

    可能有点抽象,直接上图。

    

    看效果,

$('.mybox-content').scrollTop( $('.mybox-content')[0].scrollHeight );

    我使用scrollTop来对滚动条进行定位,原本应该是直接到最底部的,打印出来相应数据进行计算也是没有问题的,可是还是出现了这种情况,而且随着数据的增加,下面没滚动上去的也相应增加。

    我就很苦恼,思考了很久很久,终于想通问题关键。

    关键点就在于多出来的那部分,那么为什么多呢?是不是每一条的高度计算错误?这么想来,就对了,当聊天文本是多行的时候,就比默认的单行高度高出了一部分,而随着聊天记录的增加,多出来的这部分就随之增加。

    这么看来就凸显出上面的问题了——渲染并没有真正完成。于是我打开断点,如下:

    

    从图中我们可以看到,2 部分是渲染完成后进行的二次处理,处理完进入 3 ——滚动条置底。然而马上就要执行 3 的时候 2 部分却只有dom,没有相应的真实数据。而就像上面所说的,真实数据填入后条目的高度可能会变高,这就导致了滚动条不能置底。

    问题明白了,解决办法就简单了。

    

setTimeout(function(){
$('.mybox-content').scrollTop( $('.mybox-content‘)[0].scrollHeight );
}, 1);

    只需要把代码放到一个延时器中就可以了,延时时间,1ms。。。。

angular中关于自定义指令——repeat渲染完成后执行动作的更多相关文章

  1. angular指令监听ng-repeat渲染完成后执行自定义事件方法

    今天工作中遇到需要用到ng-repeat遍历渲染完后执行某个操作,angular本身并没有提供监听ng-repeat渲染完成的指令,所以需要自己创建自定义指令. 在ng-repeat模板实例内部会暴露 ...

  2. 在vue中创建自定义指令

    原文:https://dev.to/ratracegrad/creating-custom-directives-in-vue-58hh 翻译:心上有杨 指令是带有 v- 前缀的特殊属性.指令的作用是 ...

  3. angular自定义指令 repeat 循环结束事件;limitTo限制循环长度、限定开始位置

    1.获取repeat循环结束: 自定义指令: .directive('repeatFinish', function () { return { link: function (scope, elem ...

  4. 利用angular指令监听ng-repeat渲染完成后执行脚本

    业务中有时需要在异步获取数据并用ng-repeat遍历渲染完页面后执行某个操作,angular本身并没有提供监听ng-repeat渲染完成的指令,所以需要自己动手写.有经验的同学都应该知道,在ng-r ...

  5. Angular.js之自定义指令学习笔记

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  6. 在Vue中通过自定义指令获取元素

    vue.js 是数据绑定的框架,大部分情况下我们都不需要直接操作 DOM Element,但在某些时候,我们还是有获取DOM Element的需求的: 在 vue.js 中,获取某个DOM Eleme ...

  7. Vue2自定义指令改变DOM值后未刷新data中绑定属性的值

    标签(空格分隔): Vue 自定义指令用于过滤输入框,只允许输入数字: Vue.directive('numberOnly', { bind: function (el, binding) { el. ...

  8. angular5中的自定义指令(属性指令)

    属性型指令用于改变一个 DOM 元素的外观或行为. 在 Angular 中有三种类型的指令: 组件 — 拥有模板的指令 结构型指令 — 通过添加和移除 DOM 元素改变 DOM 布局的指令 属性型指令 ...

  9. angular中的ng-bind-html指令和$sce服务

    angular js的强大之处之一就是他的数据双向绑定这一牛B功能,我们会常常用到的两个东西就是ng-bind和针对form的ng-model.但在我们的项目当中会遇到这样的情况,后台返回的数据中带有 ...

随机推荐

  1. caffe的调试技巧 和 使用split层

    1.网络中的layer层的输出,只要没有作为其他层的输入,caffe的日志就会把这个top输出(如果你用那个网站画网络结构图,你也会发现这种情况的层的颜色是不一样的,是紫色的) 2.如果你想看某一层在 ...

  2. file-leak-detector(文件句柄泄漏)在JDK1.6环境下 weblogic 和 tomcat安装方式以及使用方式

    file-leak-detector作者博客详见: http://file-leak-detector.kohsuke.org/ file-leak-detector学习贴: https://blog ...

  3. Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/dispatcher-servlet.xml]

    这是因为我把 [/WEB-INF/dispatcher-servlet.xml]的位置换成了[config/springmvc/dispatcher-servlet.xml] 因此idea在原来的位置 ...

  4. 修改visual studio setup 安装顺序(解决新版安装包无法自动移除老版本程序的问题)

    背景 visual studio setup 支持自动删除之前版本的安装,需要设置RemovePreviousVersions = true, DetectNewerInstalledVersion ...

  5. vs编译obj给delphi用

    Cl /O2  /c  bjhash.cpp  记得cl x32 和cl x64的区别

  6. 【数位dp】bzoj1833: [ZJOI2010]count 数字计数

    数位dp姿势一直很差啊:顺便庆祝一下1A Description 给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次. Input 输入文件中仅包含一行两个整数a ...

  7. [LUOGU] 1002 过河卒

    题目描述 棋盘上A点有一个过河卒,需要走到目标B点.卒行走的规则:可以向下.或者向右.同时在棋盘上C点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点.因此称之为"马拦过 ...

  8. [HIHO] 1050 树中的最长路

    #1050 : 树中的最长路 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上回说到,小Ho得到了一棵二叉树玩具,这个玩具是由小球和木棍连接起来的,而在拆拼它的过程中, ...

  9. windows 下phpstudy 升级mysql版本5.7

    今天在导入sql文件的时候遇到了sql执行错误.最后找到原因是因为mysql版本过低,导致出错 原因:在执行sql的时候出现了两次CURRENT_TIMESTAMP ,最后得知在5.7版本之前都是不支 ...

  10. OpenWrt 路由器如何让 lan 口主机获得 ipv6 网络访问 -- 知乎

    本文转自知乎: OpenWrt 路由器如何让 lan 口主机获得 ipv6 网络访问? - mistforest的回答 - 知乎https://www.zhihu.com/question/29667 ...