UC九游 天猪(atian25) http://atian25.github.io https://github.com/atian25 AngularJS 进阶实践 UC九游 天猪(atian25) http://atian25.github.io https://github.com/atian25
摆脱思维定势 深入理解框架 性能陷阱 AngularJS进阶
摆脱思维定势 传统前端开发思维 新一代前端开发思维 以JQuery为代表 以DOM为中心 关注VIEW层的变化和用户操作 摆脱思维定势 传统前端开发思维 新一代前端开发思维 以JQuery为代表 以DOM为中心 关注VIEW层的变化和用户操作 「我有这样一个DOM,我想让它做XX」 以AngularJS为代表 以Data为中心 聚焦于数据的变更 MVW = Model + View + WhatEver 推荐阅读: http://stackoverflow.com/questions/14994391/how-do-i-think-in-angularjs-if-i-have-a-jquery-background 翻译版本: http://blog.jobbole.com/46589/
请回忆一下 ... 实现一个下拉框(三级+级联) ,需要多少代码? 实现一个表格(分页+过滤+排序+编辑),需要多少代码? 请回忆一下 ... 实现一个下拉框(三级+级联) ,需要多少代码? 实现一个表格(分页+过滤+排序+编辑),需要多少代码? 实现一个树形菜单(可缩展+级联选择),需要多少代码? 实现一个购物车(商品展示+加入/移除购物车+修改数量+实时计算总价) ,需要多少代码? ngnice.com/showcase/#/table/local?utm_source=TZ ngnice.com/showcase/#/tree/checkbox?utm_source=TZ ngnice.com/showcase/#/integrated/cart?utm_source=TZ
实现一个下拉框(三级+级联) ,需要多少代码? http://www.ngnice.com/showcase/#/select/cascade?utm_source=TZ JQuery程序猿 AngularJS攻城狮 分别监控下拉框A/B/C的change事件 在事件中,取得下级的引用 查询符合上级筛选条件的下级数据 循环,更新下级的数据,更新下下级的数据 ... 定义下拉框A的数据源和model 定义下拉框B的数据源和model 在$watch里更新model引用 怎么也要百来行吧? 10行!
实现一个表格,需要多少代码? 分页 过滤 排序 编辑 JQuery程序猿 AngularJS攻城狮 用第三方组件吧,自己写累死人 80行! http://www.ngnice.com/showcase/#/table/local?utm_source=TZ JQuery程序猿 AngularJS攻城狮 用内置ngRepeat渲染 用内置filter过滤器过滤 用内置orderBy排序 使用自定义paging分页 无第三方组件,手写几十行代码 用第三方组件吧,自己写累死人 80行!
实现一个树形菜单,需要多少代码? 级联选择 显示/隐藏 JQuery程序猿 AngularJS攻城狮 用第三方组件吧,自己写累死人 40行! http://www.ngnice.com/showcase/#/tree/checkbox?utm_source=TZ JQuery程序猿 AngularJS攻城狮 用内置ngRepeat渲染 用内置ngClass/ngShow缩展 用内置ngInclude无限嵌套 用内置ngAnimate做动画 用第三方组件吧,自己写累死人 40行!
实现一个购物车,需要多少代码? 商品展示 加入/移除购物车 修改数量 实时计算总价 JQuery程序猿 AngularJS攻城狮 http://www.ngnice.com/showcase/#/integrated/cart?utm_source=TZ JQuery程序猿 AngularJS攻城狮 用内置ngRepeat渲染 仅仅操作数据即可 又得加班了... 60行!
摆脱思维定势 - 总结 剁手 !!! 时刻以数据为中心进行思考 再看到乱操作DOM 除了Directive,其他地方决不能操作DOM 摆脱思维定势 - 总结 Thinking in Angular 时刻以数据为中心进行思考 构思数据结构 构思操作逻辑,声明式 双向绑定VIEW,慎用逻辑 忘记「我有这么一个DOM,我想让它实现XXX」 除了Directive,其他地方决不能操作DOM 善于内置指令组合,适当写自定义指令 再看到乱操作DOM 剁手 !!!
Look Inside – 启动过程 浏览器载入HTML,解析成DOM 加载Angular类库 DOMContentLoaded事件中开始bootstrap 寻找 ng-app, 注入服务 编译DOM并链接到对于的scope数据
Look Inside – 执行期 浏览器等待用户事件触发(用户交互,定时器,网络事件…) 浏览器执行事件回调,进入Javascript上下文 Angular在$apply中接管了JS的执行部分 Angular进入$digest循环 Angular进行脏数据检查 批量更新DOM,$digest结束 浏览器开始渲染
Look Inside – 执行期示例 编译期 执行期 Angular解析Directive: input[text] 解析ng-model并为input绑定key事件 为{{vm.name}}建立$watch表达式,进行监听 执行期 用户在input输入按键,触发了浏览器的key事件 事件回调, 进入Javascript上下文 angular接管,在$apply中修改scope的name取值 触发$digest流程 脏数据检测,发现$watch列表中的name值变更 通知对应的处理函数, 更新DOM Angular退出执行上下文,退出Javascript的事件处理函数
Look Inside – Other 脏数据检查 != 轮询检查更新 https://docs.angularjs.org/guide/concepts http://angular-tips.com/blog/2013/08/watch-how-the-apply-runs-a-digest/ https://github.com/angular/angular.js/wiki/Understanding-Scopes
性能优化 提速 $digest cycle 尽少的触发$digest 尽快的执行$digest 优化ngRepeat 限制列表个数(filter/page) ngInfiniteScroll 单向绑定 不能超过2000个双向绑定 BindOnce插件 内建支持(1.3.x+) 慎用filter和事件 更多参见:http://atian25.github.io/2014/05/09/angular-performace/
Some Tips - $apply的那些事 永远忘不掉你:「Error: $apply already in progress」 反模式: if (!$scope.$$phase) $scope.$apply(); 理解$apply的场景 需要使用它的场景,很少很少: Directive里面的element.bind WebSocket.on 事件 第三方插件修改DOM或数据后 Workaround:使用$timeout(fn, 0); https://github.com/angular/angular.js/wiki/When-to-use-$scope.$apply() http://jimhoskins.com/2012/12/17/angularjs-and-apply.html
Some Tips – 原型链的坑 理解Scope原型链 https://github.com/angular/angular.js/wiki/Understanding-Scopes 使用controllerAs语法糖 http://www.cnblogs.com/whitewolf/p/3493362.html ngModel必须有「 . 」 避免原型链继承的坑 即不能直接赋值为$scope上的基本类型 需包含一个点,即“userInfo.name"
Some Tips – 装饰模式 使用场景:需要对原生/第三方的Service/Directive进行修改时 http://briantford.com/blog/angular-hacking-core 示例:http://plnkr.co/edit/cLUSw27TuB0iFx6er5l2?p=preview
Some Tips – 动态加载 动态加载controller/service/… 动态加载module 主要原理: 在config期保存$controllerProvider/$provide等引用 监听ngRoute的$routeChangeStart事件 利用route的resolve去动态加载 https://github.com/atian25/angular-lazyload 动态加载module hack module的加载机制 https://github.com/ocombe/ocLazyLoad
Some Tips – ngInclude作用域 常见需求: 同一个页面include多个模板,但需要不同的model 分析: Template中的变量名称一样,但在父模板中要用不同的model 故需要有多级scope,每个template关联到一个scope 方案: ngInit <div ng-include ="'partials/addressform.html'" ng-init="type='billing'"></div> onload <div ng-include ="'partials/addressform.html'" onInclude="type='billing'"></div> Directive scope: true
案例展示 - ngshowcase http://ngnice.com/showcase/?utm_source=TZ https://github.com/angular-cn/ng-showcase/
案例展示 - worktile https://worktile.com/?utm_source=TZ
案例展示 - 2048 http://www.ng-newsletter.com/posts/building-2048-in-angularjs.html
Join us liuyong3@ucweb.com 前端攻城狮 最前沿的技术(Angular + NodeJS) 移动互联网 Android Android技术痴迷者 加入高大上的游戏平台客户端研发