前言
近期一直在玩Angularjs,不得不说,相对于Knockout,Angularjs这一MVVM框架更强大,也更复杂,各种教程网上到处都是,不过真正用到项目的时候会遇到各种坑。
一、ng-repeat
ng-repeat 用于标识某个 elem 需要重复输出,同时重复输出的内容需为唯一
<div ng-app="app" ng-controller="control"> <h3 ng-repeat="content in repeatContent">ng-repeat: {{ content }}</h3> </div>
let app = angular.module("app", []); app.controller("control", ($scope) => { // 输出李滨泓 $scope.repeatContent = ["李", "滨", "泓"]; // 下面存在两个“泓”,会报错 // $scope.repeatContent = ["李", "滨", "泓", "泓"]; })
二、provider, service, factory 之间的关系
factory
factory 很像 service,不同之处在于,service 在 Angular 中是一个单例对象,即当需要使用 service 时,使用 new 关键字来创建一个(也仅此一个)service。而 factory 则是一个普通的函数,当需要用时,他也仅仅是一个普通函数的调用方式,它可以返回各种形式的数据,例如通过返回一个功能函数的集合对象来将供与使用。
定义:
let app = angular.module("app", []); // 这里可以注入 $http 等 Provider app.factory("Today", () => { let date = new Date(); return { year: date.getFullYear(), month: date.getMonth() + 1, day: date.getDate() }; });
使用注入:
app.controller("control", (Today) => { console.log(Today.year); console.log(Today.month); console.log(Today.day); });
service
service 在使用时是一个单例对象,同时也是一个 constructor,它的特点让它可以不返回任何东西,因为它使用 new 关键字新建,同时它可以用在 controller 之间的通讯与数据交互,因为 controller 在无用时其作用域链会被销毁(例如使用路由跳转到另一个页面,同时使用了另一个 controller)
定义:
let app = angular.module("app", []); // 这里可以注入 $http 等 Provider // 注意这里不可以使用 arrow function // arrow function 不能作为 constructor app.service("Today", function() { let date = new Date(); this.year = date.getFullYear(); this.month = date.getMonth() + 1; this.day = date.getDate(); });
使用注入:
app.controller("control", (Today) => { console.log(Today.year); console.log(Today.month); console.log(Today.day); });
provider
provider 是 service 的底层创建方式,可以理解 provider 是一个可配置版的 service,我们可以在正式注入 provider 前对 provider 进行一些参数的配置。
定义:
let app = angular.module("app", []); // 这里可以注入 $http 等 Provider // 注意这里不可以使用 arrow function // arrow function 不能作为 constructor app.provider("Today", function() { this.date = new Date(); let self = this; this.setDate = (year, month, day) => { this.date = new Date(year, month - 1, day); } this.$get = () => { return { year: this.date.getFullYear(), month: this.date.getMonth() + 1, day: this.date.getDate() }; }; });
使用注入:
// 这里重新配置了今天的日期是 2015年2月15日 // 注意这里注入的是 TodayProvider,使用驼峰命名来注入正确的需要配置的 provider app.config((TodayProvider) => { TodayProvider.setDate(2015, 2, 15); }); app.controller("control", (Today) => { console.log(Today.year); console.log(Today.month); console.log(Today.day); });
三、handlebars 与 angular 符号解析冲突
场景:
当我使用 node.js 作为服务端,而其中使用了 handlebars 作为模板引擎,当 node.js 对某 URL 进行相应并 render,由于其模板使用 { {} } 作为变量解析符号。同样地,angular 也使用 { {} } 作为变量解析符号,所以当 node.js 进行 render 页面后,如果 { {} } 内的变量不存在,则该个区域会被清空,而我的原意是这个作为 angular 的解析所用,而不是 handlebars 使用,同时我也想继续使用 handlebars,那么此时就需要将 angular 默认的 { {} } 解析符号重新定义。即使用依赖注入 $interpolateProvider 进行定义,如下示例:
app.config($interpolateProvider => { $interpolateProvider.startSymbol('{[{'); $interpolateProvider.endSymbol('}]}'); });
四、ng-annotate-loader
ng-annotate-loader 应用于 webpack + angular 的开发场景,是用于解决 angular 在进行 JS 压缩后导致依赖注入失效并出现错误的解决方法
安装
$ npm install ng-annotate-loader --save-dev
配置
// webpack.config.js { test: /\.js"color: #ff0000">五、双向数据绑定
当我们使用非 Angular 自带的事件时,$scope 里的数据改变并不会引起 $digest 的 dirty-checking 循环,这将导致当 model 改变时,view 不会同步更新,这时我们需要自己主动触发更新
HTML
<div>{{ foo }}</div> <button id="addBtn">go</button>JavaScript
app.controller("control", ($scope) => { $scope.foo = 0; document.getElementById("addBtn").addEventListener("click", () => { $scope.foo++; }, false); })很明显,示例的意图是当点击 button 时,foo 自增长并更新 View,但是实际上,$scope.foo 是改变了,但是 View 并不会刷新,这是因为 foo 并没有一个 $watch 检测变化后 $apply,最终引起 $digest,所以我们需要自己触发 $apply 或者创建一个 $watch 来触发或检测数据变化
JavaScript(使用 $apply)
app.controller("control", ($scope) => { $scope.foo = 0; document.getElementById("addBtn").addEventListener("click", () => { $scope.$apply(function() { $scope.foo++; }); }, false); })JavaScript(使用 $watch & $digest)
app.controller("control", ($scope) => { $scope.foo = 0; $scope.flag = 0; $scope.$watch("flag", (newValue, oldValue) => { // 当 $digest 循环检测 flag 时,如果新旧值不一致将调用该函数 $scope.foo = $scope.flag; }); document.getElementById("addBtn").addEventListener("click", () => { $scope.flag++; // 主动触发 $digest 循环 $scope.$digest(); }, false); })六、$watch(watchExpression, listener, [objectEquality])
注册一个 listener 回调函数,在每次 watchExpression 的值发生改变时调用
watchExpression 在每次 $digest 执行时被调用,并返回要被检测的值(当多次输入同样的值时,watchExpression 不应该改变其自身的值,否则可能会引起多次的 $digest 循环,watchExpression 应该幂等)
listener 将在当前 watchExpression 返回值和上次的 watchExpression 返回值不一致时被调用(使用 !== 来严格地判断不一致性,而不是使用 == 来判断,不过 objectEquality == true 除外)
objectEquality 为 boolean 值,当为 true 时,将使用 angular.equals 来判断一致性,并使用 angular.copy 来保存此次的 Object 拷贝副本供给下一次的比较,这意味着复杂的对象检测将会有性能和内存上的问题
七、$apply([exp])
$apply 是 $scope 的一个函数,用于触发 $digest 循环
$apply 伪代码
function $apply(expr) { try { return $eval(expr); } catch (e) { $exceptionHandler(e); } finally { $root.$digest(); } }使用 $eval(expr) 执行 expr 表达式
如果在执行过程中跑出 exception,那么执行 $exceptionHandler(e)
最后无论结果,都会执行一次 $digest 循环
总结
以上就是这篇文章的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 【雨果唱片】中国管弦乐《鹿回头》WAV
- APM亚流新世代《一起冒险》[FLAC/分轨][106.77MB]
- 崔健《飞狗》律冻文化[WAV+CUE][1.1G]
- 罗志祥《舞状元 (Explicit)》[320K/MP3][66.77MB]
- 尤雅.1997-幽雅精粹2CD【南方】【WAV+CUE】
- 张惠妹.2007-STAR(引进版)【EMI百代】【WAV+CUE】
- 群星.2008-LOVE情歌集VOL.8【正东】【WAV+CUE】
- 罗志祥《舞状元 (Explicit)》[FLAC/分轨][360.76MB]
- Tank《我不伟大,至少我能改变我。》[320K/MP3][160.41MB]
- Tank《我不伟大,至少我能改变我。》[FLAC/分轨][236.89MB]
- CD圣经推荐-夏韶声《谙2》SACD-ISO
- 钟镇涛-《百分百钟镇涛》首批限量版SACD-ISO
- 群星《继续微笑致敬许冠杰》[低速原抓WAV+CUE]
- 潘秀琼.2003-国语难忘金曲珍藏集【皇星全音】【WAV+CUE】
- 林东松.1997-2039玫瑰事件【宝丽金】【WAV+CUE】