AngularJS1.X版本基础

AngularJS  知识点

DataBinding Providers Validators Directives

Controllers Modules Expressions Factories

Services Filters Dependency Injection Scope

AngularJS优缺点比较

优点

MVVM 数据和视图绑定,省去频繁操作jquery更新dom,自带了丰富的Angular指令,整体功能比较完善,

包含模板,数据双向绑定,路由,模块化,服务,过滤器,依赖注入等所有功能

自定义Directive组件,组件化,模块化

引入后台开发的一些概念,MVC,服务,依赖注入 ,容易构建SPA单页面应用

文档丰富,生态圈相对较好,问题容易解决

缺点

相比jquery,代码侵入性过大,依赖太多而且剥离升级困难,另外与jquery组件冲突严重,需要$apply()

directive一些指令生命周期定义复杂,容易如门但学习曲线陡峭

本身有些自带指令ng-route不好用,要依赖第三方,ui router仍旧问题太多,复杂路由很难用

版本迭代变化太大,2.0完全颠覆以前东西,甚至都不能说是同一个框架,1.x设计有问题(同第一条)

MVVM

 Module

1<script src="../../../resources/plugin/angular/angular.min.js"></script> 2 3var studyApp = angular.module("studyApp", ["pascalprecht.translate", "kendo.directives", "wl.directives", "wl.controls", "study.controls", 'ui.router', "oc.lazyLoad"]); 4studyApp.controller("frameController", function ($http, $scope, $timeout, $state, $translate, $filter, $rootScope) { 5 //省略........ 6});

AngularJS允许我们使用angular.module()方法来声明模块,

这个方法能够接受两个参数,第一个是模块的名称,第二个是依赖的模块列表,也就是可以被注入到模块中的对象列表。

angular.module('myApp', []); 用来定义模块**,相当于AngularJS模块的setter**方法。

调用这个方法时如果只传递一个参数,就可以用它来引用模块。

angular.module('myApp') ; 用来获取对myApp模块的引用,相当于AngularJS模块的getter方法,。

1var planApp = angular.module("planApp"); 2planApp.controller("strContentCtrl", function($rootScope,$http,$scope,$timeout,$state,$stateParams,$transitions,$filter){ 3 //省略...... 4});

Module的使用

(Recommended Setup)推荐设置

大规模的应用,建议将自己的应用按照如下建议,拆分为多个module:

service module,用于声明service。

directive module,用于声明directive。

filter module,用于声明filter。

应用级别的module,依赖上述的module,并且包含初始化的代码。

自带指令

ng-app 、ng-repeat、ng-model,ng-bind、ng-click、

ng-show、ng-change、ng-focus、ng-src、ng-class、

ng-include、ng-mouseover, ng-mouseout, ng-mouseleave,ng-mouseenter

ng-init <div ng-init=“quantity=1;price=5”> 不常用

Databinding及表达式

AngularJS 表达式写在双大括号内:{{ expression }}

AngularJS 表达式把数据绑定到 HTML,这与 ng-bind 指令有异曲同工之妙。

AngularJS 将在表达式书写的位置"输出"数据。

AngularJS 表达式 很像 JavaScript 表达式:它们可以包含文字、运算符和变量。

实例 {{ 5 + 5 }}{{ firstName + " " + lastName }}

推荐使用ng-bind, {{ expression **}}**在页面加载完成之前,页面会出现表达式的乱码

1<div ng-app=""><p>姓名: {{ firstName + " " + lastName }} </p> 2<p>总价: <span ng-bind="quantity * cost“ ></span></p></div>

Controller

1<body ng-app="studyApp" ng-controller="frameController"> 2 3studyApp.controller("frameController", function ($http, $scope, $timeout, $state, $translate, $filter, $rootScope) { 4 //省略...... 5});

一个页面或者一块独立功能区域都可以对应一个controller,即MVC中的C页面model和相应页面的逻辑处理js,写在这里

PS:$scope即当前controller的独立作用域,相关页面变量和方法可以放在里面,类似于jquery自执行函数的闭包,起到封闭作用域的作用

Factory方式创建的服务,作用就是返回一个有属性有方法的对象。相当于:var f = myFactory();

1//创建模型 2var app = angular.module('myApp', []); 3//通过工厂模式创建自定义服务 4app.factory('myFactory', function ()) { 5 var service = {}; 6 //定义一个Objedct对象 7 service.name = "王子"8 var age; //定义一个私有化的变量 9 //对私有属性写getter、setter方法 10 service.setAge = function (newAge) { 11 age = newAge; 12 } 13 service.getAge = function (newAge) { 14 return age; 15 } 16 return service; //返回这个Object对象 17});

Service即提供一个服务,可以认为是JAVA里面的一个Utils类,而且是static的,因为只会有一个实例。类似JS的自执行函数并且返回自身对象

provider()是创建service最底层的方式,这也是唯一一个可以使用**.config**()方法配置创建service的方法;(angularjs translate即采用provider方式)

与 factory 和 service 稍有不同的是, provider 必须有一个 $get 方法, $get 方法和 factory 要求是一致的, 即: 先定义一个对象, 给这个对象添加属性和方法, 然后返回这个对象

provider()不同于service()和factory(),在注入其他的服务的时候不能在function()中依赖注入;

这是唯一能注入到config的service,这样定义的service在你开始注入之前就已经实例化,开发共享的模块的时候常常使用它,能够在使用之前进行配置,

例如 配置服务端的url

 例如 配置多语言参数

1planAuditApp.config(["$translateProvider",function($translateProvider) { 2 // 对接菜单URL的多语言参数 3 var lang = WLJS.getQueryString("lang"); 4 STUDY_COMM.initNGTranslate($translateProvider, lang, [ 5 "studytemplatelist", 6 "common" 7 ]); 8 } 9]);

Provider定义方法:

1app.provider('MyProvider', function () { 2 this.$get = function () { 3 var result = {}; 4 result.greeting = 'hello from provider'; 5 teturn result; 6 } 7});

 使用方法:

1app.controller('myCtrl', function($scope,MyProvider) { 2 $scope.onclick = function () { 3 MyProvider('Provider test'); 4 }; 5});

Factory,Service,Provider区别总结

Factory返回的是一个对象,即设计模式的工厂模式,每次由工厂new一个对象

Service返回的是this本身,只需要对this的对象及方法进行设置即可,只会实例化一次,相当于一个static的Utils类;

Provider返回的是一个$.get方法,主要作用还是可以config里提前配置在service和factory之前执行

Filter****可以用在html标签表达式里面,比如自定义一个字符串过长省略号的过滤器

1planControls.filter('cut', function() { 2 return function(value, wordwise, max, tail) { 3 if (!value) return ''; 4 5 max = parseInt(max, 10); 6 if (!max) return value; 7 if (value.length <= max) return value; 8 //原方案未考虑到中英文字符串长度不同 9 //value = value.substr(0, max); 10 //wordWise:对于英文等有空格的短语,将残缺的单词去掉 11 var realValue = ''; 12 var realLength = 0, 13 len = value.length, 14 charCode = -1; 15 for (var i = 0; i < len; i++) { 16 charCode = value.charCodeAt(i); 17 if (charCode >= 0 && charCode <= 128) 18 realLength += 1; 19 else 20 realLength += 2; 21 if (realLength > max) 22 break; 23 else 24 realValue += value.charAt(i); 25 } 26 if (wordwise) { 27 var lastspace = realValue.lastIndexOf(' '); 28 if (lastspace != -1) { 29 realValue = realValue.substr(0, lastspace); 30 } 31 } 32 return realValue + (tail || ' …'); 33 }; 34});

 使用:{{**  |  }}**

 <span title="{{plan.name}}" ng-bind="(plan.name | cut:true:20:'...')">

Angular controller通信

此处只涉及同一个dom,单页面,采用事件通信方式

如果一个页面有多个dom,仍旧采用js iframe的方式

Controller通信采用事件方式,事件有两种,emitbroadcast

broadcast方式与emit方式的区别:

broadcast方式一种广播模式,就是父级发送一个消息时间,子级controller里面监听这个消息事件的函数就会执行;

emit与$broadcast方式相反,是子级controller发布一个消息事件,父级controller监听的函数执行;

注意同一个controller里面都是可以捕获到消息事件的; 但平级之间不能,平级之间可以通过parent中继,先emit再broadcast,不过看有文档说broadcast耗资源过多,路由过于复杂时不宜过多使用

Directive自定义指令,实现html标签的指令解析, 控件

一个例子:

1<my-directive show-score="true" ng-model="dataStore.basicPoint"></my-directive> 2 3planControls.directive('myDirective', function() { 4 return { 5 restrict: 'E', //表示该directive仅能以element方式使用,即:<basicinfopoing></basicinfopoing> templateUrl: WLJS.getWebRoot() + "/views/study/directive/basicinfopoint.html", replace: true, scope: { //创建一个新的“隔离”scope,通过绑定与父scope通信 6 7 ngModel: "=", //双向绑定,外部scope和内部scope的model能够相互改变,字符串和对象都可以 8 showScore: "=" 9 }, 10 controller: function($scope, $element, $filter) { 11 $scope.init = function(point) { 12 if (point > 10 || point < 0) { 13 return; 14 } 15 var cans = $('#basicInfoCanvas'); 16 var ctx = cans[0].getContext('2d'); 17 ctx.clearRect(0, 0, 300, 150); 18 19 var bigx = 150; 20 var bigy = 75; 21 var bigr = 60; 22 23 // 外圆轮廓 24 ctx.beginPath(); 25 ctx.arc(bigx, bigy, bigr + 15, 0, 2 * Math.PI, false); 26 ctx.strokeStyle = '#DCDCDC'; 27 ctx.lineWidth = 1; 28 ctx.stroke(); 29 ctx.closePath(); 30 //省略...... 31 } 32 $scope.$watch('ngModel', function() { 33 $scope.init($scope.ngModel); 34 }); 35 36 $scope.showAuditScoreWindow = function() { 37 $scope.$emit("showAuditScoreWindow"); 38 } 39 } 40 }; 41});

restrict:

E: 表示该directive仅能以element方式使用,即:<my-directive></my-directive>

A: 表示该directive仅能以attribute方式使用,即:<div my-directive></div>

C: 表示该directive仅能以class方式使用,即:<div class="my-directive"></div>

EA: 表示该directive既能以element方式使用,也能以attribute方式使用

注意,命名规则,不要使用大写,html标签不支持大写,另外,“-”会被忽略

template或者templateUrl:  div or url

replace:  true or false

scope: 默认false直接使用父scope.

true:继承父scope.

{ }:创建一个新的“隔离”scope,通过绑定与父scope通信.

Scope绑定的策略,有3种:

@:单向绑定,外部scope能够影响内部scope,但反过来不成立,

只能当字符串传递,绑定外层scope的值

for-name="{{ Name }}"

1scope:{ 2 3 name:'@forName' 4 5 }

也可以这样写name:'@', 这样写的话,就默认DOM中的属性名为name,即for-name="{{ Name }}"可简写为name="{{ Name }}";,另外两个符号=和&也有这样的简写规则,方便起见接下来都使用这种写法。

=:双向绑定,外部scope和内部scope的model能够相互改变,字符串和对象都可以

&:传递一个来自父scope的函数(即对父级作用域进行绑定,并将其中的属性(可以是任何属性)包装成一个函数),稍后调用;

1<hello method="sayName(name)"></hello> 2 3scope: { 4 5 method:'&' //得到了父scope的sayName()方法 6 7}

Directive的生命周期:

执行顺序:

controller->compile ->link

compile是对指令的模板进行替换,dom操作

link是在模型和视图中建立关联,注册监听事件

对于多个实例,compile只会执行一次,执行template替换,而link每个实例执行一次

compile返回的是一个函数,即link函数,如果使用compile,link会被忽略

controllers用于多个指令的交互,和require结合使用

路由管理 ng-router

Angularjs自带路由ng-route,官方路由

1<div ng-view>区块1</div> 2<div ng-view>区块2</div> 3 4$routeProvider.when('/', { 5 template: 'hello world' 6}); //不能指定ng-view

视图没有名字进行唯一标识,所以它们被同等的处理,不支持多视图路由

不支持嵌套路由

路由管理 UI-Router

https://ui-router.github.io/

多路由:

页面html引入,ui-view后面即路由id

1<!-- index.html --><body> 2<div ni-view="filters"></div> 3<div ni-view="tabledata"></div> 4<div ni-view="graph"></div> 5<body>

路由定义,每一个路由**{ }里面都可以定义url**,template,cachecontroller等配置

子路由相应的js和css引入方式:

html加载时一次性引入,写在一个文件里面,或者用webpack之类的打包工具

利用oclazyload之类的第三方组件实现懒加载,动态加载

1studyApp.config([ 2 "$stateProvider", 3 function ($stateProvider, $scope) { 4 $stateProvider.state( 5 stepurl[0], { 6 url: stepurl[0], 7 templateUrl: actionType != "view" ? '../../../views/study/studyinformationedit.html' : '../../../views/study/publishedstudyinformation.html', cache: 'false', 8 params: { 9 id: study_id, 10 actionType: actionType, 11 scene: scene 12 }, 13 resolve: { 14 load: [ 15 '$ocLazyLoad', 16 function ($ocLazyLoad) { 17 return $ocLazyLoad.load([actionType != "view" ? '../../../resources/js/study/studyinformationedit.js' : '../../../resources/js/study/publishedstudyinformation.js', ]); } 18 ] 19 } 20 }).state(stepurl[1], { 21 url: stepurl[1], 22 templateUrl: '../../../views/study/publishedstudyworkflow.html' + "?id=" + study_id + "&actionType=" + actionType, cache: 'false', 23 params: { 24 id: study_id, 25 actionType: actionType, 26 scene: scene 27 }, 28 resolve: { 29 load: ['$ocLazyLoad', function ($ocLazyLoad) { 30 return $ocLazyLoad.load(['../../../resources/js/study/publishedstudyworkflow.js', '../../../resources/js/study/flownodefig.js']); }] 31 } 32 }) 33 34 } 35]);

 嵌套路由

主页面及路由定义

一级子页面PageTab.html

 二级子页面page1.html和page2.html

路由跳转方式

Ui-serf html超链接

1<a ui-sref="parent">点我显示父view内容</a> 2<a ui-sref="parent.child">点我显示父view与子view内容</a>

Js跳转

$state.go (‘parent.child’, parms, {reload:true}):

// $state.go 只刷新子路由有bug

// $state.go("a.b",{},{reload:"a.b"})api文档说是只刷新b路由,

// 但当前已经是a.b路由的时候, 此时有需要重复进入自路由,即从a.b到a.b,但a.b==a.b, reload子路由不会执行

// 增加一级三级路由,$state.go("a.b.c",{},{reload:"a.b"}),

// 此时当前路由a.b.c!=a.b,可以绕过此bug

// reload是强制刷新,true或者false, 后面加url实现刷新子路由改变了reload的含义,reload本身失效,Github提过issue,无果

Angular与Jquery一些思考

在用angularjs时,必须先知道的,angularJs 本身设计与Jquery不一样,甚至是冲突的,Jquery是尽量方便的让开发着操作DOM,呈现页面给用户;

而angualrjs更注重数据的页面展示及mvvm, 强调一个原则,即所有界面都是自定义控件directive构成,对dom的操作都要封装在directive里面进行controller要避免操作dom

jquery的控件和angularjs一起会遇到很多问题,jquery的控件不会触发mvvm绑定,有时候;jquery也极其容易封装自定义控件,控件的封装并不是angular的特色;

jquery因其拥有对dom操作的简单方便特性, 同时开发者没有强调控件的封装,很多初学者在页面js里面随意操作dom,造成js代码很乱,不规范;这并不是jquery的缺陷,而是使用者的问题。

对DOM的操作是基础,开发人员还是要熟悉; angularJS的一些指令集的实现,比如ng-repeat, 里面也是对dom的操作,不过其用了jquery的一个简化后轻量级版本,叫jqlite,和jquery大同小易, 方法名也差不多;

angularjs不推荐用jquery来操作元素,个人认为,看个人喜好,jquery的应用更广泛,个人开发者没有必要再换个小众版本的jqlite;

Angularjs版本迭代太快,angular1.0和angular2.0是整体架构设计的变更,完全不向下兼容,甚至  严格来说并不是一套框架; 而且,angualrjs对代码侵入性太大,学习曲线陡峭,

所以相对的对 angularjs的使用要慎重,框架还是太重了,存在和jquery控件兼容性及取舍问题。

PS:个人更倾向于Vue作者尤雨溪,渐进式前端解决方案;即:有些框架算是工具,他们的存在是为了帮助我们应对系统复杂度,增加开发效率;所以,在框架的复杂度和带来的开发效率中要做一个权衡,如果框架使用过于复杂,代码侵入性过大,要慎重选择;angularjs1.x有些设计过于复杂,不易学习使用,2.x进行了大部分重构和优化,借鉴了 Vue、React等的一些设计;大家有空可以看下其他优秀前端框架;angular1.x与2.x以后的版本基本不能算一个东西;

试想不用angularjs,我们的系统是不是能保证代码质量下,开发效率更快,性能更好?

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

swap空间的增减方法

(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap