使用Ng的流程
<!--
1. 引入ANGULAR包
2. 定义一个模块
3. 使用ng-app载入这个模块
4. 定义需要用到的控制器
5. 设计$scope的成员(应该是页面的抽象)
6. 在模版上进行数据绑定
7. 完成业务逻辑
-->
(function(window, angular) { 为什么要将window和angualr作为参数? 因为变量搜索机制,这样就不会在外面找了,函数内就能找到。
$scope 里面有数据, angular的数据就是绑定在$scope上的
angular.module('module3', []);这里是注册
var module3 = angular.module('module3'); 不传递第二个参数是获取模块,获取module3之前必须要先注册module3。
angular中不要有dom操作,通常是用ng-model,ng-if, ng-show等指令灵活使用来替代dom操作。
面试:忌讳把死记硬背的照本宣科,说自己的体会,不确定的问题就把相关的都说一说。
使用angular.bootstrap方法手动启动模块可实现多个模块:
angular.bootstrap(document.getElementById('module1_div'),['module1'])
angular.bootstrap(document.getElementById('module2_div'),['module2'])
添加一个主要的模块,此模块直接作用于HTML中 此模块不做任何业务,只是去装载需要的模块
angular.module('mainModule',['module1', 'module2'])
ng-app在同一个HTML中只能使用一次
ng-cloak指令就是在NG执行完毕过后自动移除,她可以避免出现源码的闪烁
由于压缩代码会改变参数名称,注册控制的标准方式就是通过第二个参数传递数组的方式(数组的成员最后一个就是原本的控制器函数,前面的成员都是需要注入的对象名称)
module.controller('HelloController', ['$scope','$http', function(a,b) {
console.log(a);
}]);
Ng-model是双向绑定,{{}}是单向绑定
jqlite是angular内置的类似于jquery的。 用法很类似于jQuery。区别是:
var dom = document.getElementById('demo'); angular.element(dom).addClass('red')
根据当前页面的情况(业务块)划分控制器
如果有控制器,模型数据就在最近的控制器上,没有控制器,就在最近的ng-app上!
ng-cloak 指令的作用就是在NG执行完成过后自动移除 自动输出一段样式[ng-cloak]{display: none;}
$scope.$apply(); // 告诉ng数据模型发生了变化,需要同步, 只有在异步操作时需要调用
$apply. Ajax和setTimeout都属于异步
如果着实需要在页面上绑定 HTML 内容(不转义),就要使用 ng-bind-html 指令(依赖 ngSanitize 指令)
<li ng-repeat="(id, item) i n ps track by $index"> track by $index避免了ps数组中出现重复项的的时候不显示的问题
ng-bind和表达式效果相同,表达式会闪一下, ng-bind不会
data-属性 和 x-属性 都是自定义属性的前缀 在NG中任何一个指令都可以使用这两种前缀
表达式会自动将内容进行HTML编码化(考虑安全): HTML编码化是一种常用的安全策略
以后在程序中如果需要输出内容到页面上,考虑可不可能是一个HTML
如果可能出现HTML 一定要编码化过后再呈现
$scope 实际上就是MVVM中所谓的VM(视图模型)
- 正是因为$scope在Angular中大量使用甚至盖过了C(控制器)的概念,所以很多人(包括我)把Angular称之为MVVM框架
// todo: 实现注册逻辑 用todo注释来标记接下来要完成的事项。
调试的方式 window.$scope = $scope 这样就能在控制台直接输入$scope来调试了。
模块化总结:
1. 不应该把html和js分开,而应该按照模块把同一模块的html,js放同一个文件夹命名为该模块!
输出undefined可能是因为没有初始化,
- 必须初始化: $scope.data = {spRange: 50}
2. view和model必须对应:ng-model="data.spRange"
<input type="range" min="10" max="100" step="10">
type="datetime-local"
Ng 定时器服务
renewDevs = $interval(function () {}
$interval.cancel(renewDevs)
$scope.$apply()会自动地调用$rootScope.$digest()。
在$digest循环中,watchers会被触发。当一个watcher被触发时,AngularJS会检测scope模型。 $scope.$apply()必须放在需要执行代码的后面
同步不响应的时候,加一个$scope.$apply()即可!
$rootScope.name = 'joe' console.log($scope.name) $scope能拿到$rootScope的内容
内层控制器的作用域可以通过$parent来访问外层控制器作用域上的变量。 不要把$parent误认为是上下两级控制器之间的访问通道,从这个例子我们可以看到,并非如此,只是两级作用域而已,作用域跟控制器还是不同的,刚才的循环可以说是有两级作用域,但都处于同一个控制器之中。
ng-controller和ng-repeat都会创建新的作用域
ng-show/ng-hide是不自带作用域的,而ng-if则自己创建了一级作用域.
总结:相似的类型还有ng-switch,ng-include等等,规律可以总结,也就是那些会动态创建一块界面的东西,都是自带一级作用域。
- 在任意已有的作用域上调用$new(),就能创建一个新的作用域:var newScope = scope.$new();
AngularJS 中,服务是一个函数或对象,通常需要反复调用的就封装为一个服务!
$index:序号
过滤器 // 定义过滤器
AmanyCom.filter('description',function () {
return function (text) {
// task_status取值:0新建,1运行中,2运行完成
if (text == 0) {
return text = '新建'
}
}
})
代码不执行的时候:
1.调用setTimeout()异步执行通常会有效,但是不建议这么做!
2.对于Ng: 1)
$scope.$apply()
另一种写法:
2)
$scope.$apply
(function () {
$scope.persondata = res
})
Ng的指令中不能注入 $scope,但是可以注入$rootScope
ng-model-options 指令绑定了 HTML 表单元素到 scope 变量中
View的更改更新不到model很可能是:
1把数据放到 $scope.data.XX上。
也就是双向绑定的时候不要创建常量,用对象引用来绑定。
2.也可能是控制器太远了!
在以往的jQuery开发中,我们会首先设计页面DOM结构,然后在利用jQuery来改变DOM结构或者实现动态交互效果。因为jQuery是为DOM驱动而设计的,对于拥有大量复杂的前端交互的项目,JavaScript的逻辑变得越来越臃肿,交互逻辑分散各处。
在MVVM模式下的angular开发中, 我们首先需要在脑子里挂着Model的弦。不能老想着“我有XXX这个DOM,我希望让它做XXX这种动态效果”,我们需要从要完成的目标开始思考我们需要或拥有怎么样的Model数据,然后设计我们的应用, 最后才是设计视图,并用$scope来粘合它们。
Ng阻止冒泡方法:
angular.element("#LinkInput").bind('click', function (event) {
event.stopPropagation();
});
Dom操作直接写在对应控制器中:用angular.element包装
angular.element(document.querySelector('#fileInput')).on('change',handleFileSelect);
git当用户访问到/inbox/
时,上面的的路径会被激活,然而当访问到/inbox
时不会被激活 为什么?
ui-sref可以用于a以外的其他标签
<li><a ui-sref="^.detail">我通过相对路径到相邻的state</a></li>
<li><a ui-sref="content.photos.detail">我通过绝对路径到相邻的state</a></li>
路由思路:
使用ngRoute模块来实现SPA应用的基本步骤:
①创建完整的HTML页面 index.html,引入angular.js,angular-route.js
②创建自定义的模块,指定依赖于ng gRoute
③指定容器,盛放代码片段 ngView
④创建模板页面
⑤配置路由词典
⑥测试在地址栏中 输入不同的路由地址的时候,能否将代码片段加载进来。
模板页面之间 执行跳转的3种方式:
①直接修改地址栏中的url
②使用超链接 <a href='#/路由地址'></a>
③$location.path('/路由地址')
如果有多个代码片段,都需要通过js的方式来跳转,为每个代码片段去创建控制器 去定义jump方法,这个是不合理的,可以这么处理:借助父控制器定义方法,然后让子控制器去调用。
配置代码片段的控制器的方式:
①ng-controller
②配置路由词典设置
$routeProvider.when('/myLogin',{
templateUrl:'tpl/login.html',
controller:'loginCtrl'
});
提供了3种方法实现自定义服务
// factory、service、value
ng-repeat="name in students track by $id($index)"
angular.element把Dom元素或者HTML的字符串包装成jQuery对象,假如你在angular之前引用了jQuery,那么这就相当于jQuery的选择器了,你也可以把jQuery的一些dom操作对他使用;那么如果你就是这么任性,不引用jQuery呢?别着急,ng自带jqLite,上面也把jqLite对这个方法包装成的对象提供的一些方法都列出来了,有需要的可以去看看,不过毕竟是轻量版的,功能没那么齐全,如需更多操作,可在angular[.min].js文件之前引入jQuery文件。
angular.element() 方法可以将一个原生DOM对象转成jquery对象,注意不是转成angular对象
NG跟dom操作不同之处是,需要对模型更改数据(而非直接操作dom),然后从模型遍历出来,最后渲染到view上!
在 HTML 元素上绑定多个表达式时可以使用 ng-bind-template 指令
ngChange 和$scope.$watch的区别,ngChange 仅仅监控munally change NOT programmatically. 但是$scope.$watch都会监控。
$scope.$watch('username', function(now, old) {
// console.log(`${now}--${old}`);
if (!/^w[w_d]{5,15}$/.test(now)) {
$scope.error_message = ('用户名违规');
return;
}
$scope.error_message = '';
});
});
解决因为压缩代码造成注入对象失败问题的方式就是将第二个参数换成一个数组
.controller('DemoController', ['$scope', '$log', function($scope, $log) {
$scope.value = new Date();
$scope.do = function() {
$log.warn($scope.value);
};
}]);
即等同于:
angular.module("myapp",[]).controller("DemoController",["$scope","$log",function(a,b){a.value=new Date();a.do1=function(){b.warn(a.value)}}]);
用a代表$scope, b代表$log
AngularJS 应用在加载时,文档可能会由于AngularJS 代码未加载完而出现显示 AngularJS 代码,进而会有闪烁的效果, ng-cloak 指令是为了防止该问题的发生。
在定义指令应该使用驼峰命名法,使用指令时应该使用的是全小写字母中划线分割的方式
将控制器代码中重用的抽象为服务,
将视图中重复的代码抽象为指令
$routeProvider.when('/detail/
:id
?
', {
/*:
代表占位符,
?代表可选
(0
个或多个
)
*/
每个业务都有一个模块,都有一个文件夹分别存放MVC(module.js,view.html controller) 这三个东西,只是controller通常放在module.js内,参照moviecat案例!
指令定义必须用驼峰命名法!使用必须用
-
:
如:
定义:
.directive('upload
P
ic',function () {
使用:
<div class="upload left" upload
-p
ic>
在angular中,凡是重复的,有dom操作的,都把他定义为指令
通常angular要操作dom,一般是在link-directive指令中操作dom,getElmentById()之类的angular也可以用
todomvc案例易错点重点总结:
1. $scope.todos = Storage.get(); // x00001 重点: 这里的todos和storage服务里的todos指向同一个对象,相当于双向绑定了!!!
2. return todos; $scope.todos = temp; *产生新对象,两个todos都要重新指向这个新对象!!!*/
要不要把方法从控制器移到service.js中,主要看是否对数据进行了增删改,查数据可以不用放入
如果ng-repeat遍历的数据不显示,那么很可能是有重复项! 需要使用track by $index
当函数依赖某东西,却拿不到的时候,就只能通过传参!
<pre>{{ data | json }}</pre>
$watch只能监视$scope上的成员(不仅仅是属性,方法的返回值也可以监视)
自定义指令: 组件式指令 功能型指令
myModule.directive('hello', function() {
return {
restrict: 'E',
template: '<h1>Hello world</h1>',
replace: true
};
myApp.directive("ngHover", function() {
return function(scope, element, attrs) {
element.bind("mouseenter", function() {
element.css("background", "yellow");
});
element.bind("mouseleave", function() {
element.css("background", "none");
});
}
});
filter过滤器,实际上就是给数据格式化
- 根据界面原型抽象数据成员(有哪些数据,每个数据的类型和结构),然后抽象行为
- 设计模块,控制器
- 完成数据绑定
- 编写交互逻辑
Angular:易错点总结:
1. 不要漏步骤
2. 不要拼错单词
NG中根据请求的URL决定去执行哪个过程,这个过程称为路由。
用bootstrapcss模板的哪个组件要看整体,整体像的才是最适合的,局部不像内部还可以嵌套别的组件。有时候是一个模板套另一个模板,比如moviecat 项目中,是列表组组件内部套了个媒体对象组件。 所以必须先看整体
工作中很多项目都能在网上找一个骨架,然后基于骨架开发就行了,可以省时省事! 通常github上有很多骨架,比如html5的骨架就搜html5-boilerplate boilerplate是骨架的意思
Angular MVC实现思想: 先抽象出数据,再抽象出行为,可参考登录注册那个案例和todoMVC案例
跟列表相关的数据,要给所有的列表项加上一个id,不管暂时需不需要,以后很可能都能用到! 如下图所示
scope.$digest $scope.$apply();
$scope.$watch('username', function(now, old) {}