Angularjs的重要概念

AngularJS的重要概念

MVC模式

AngularJS最早按照MVC模式设计,在这种设计模式下,AngularJS组件可以分为:

  • M: Model,即模型,是应用程序中用于处理应用程序数据逻辑的部分,在AngularJS中:
    • 即作用域对象(当前为$rootScope), 它可以包含一些属性或方法;
    • 充当储存数据的容器;
    • 提供操作数据的方法。
  • V: View,即视图,是应用程序中用于处理数据显示的部分,在AngularJS中:
    • 即HTML页面,AngularJS提供了一些指令来增强HTML标签的作用;
    • 包括: html/css/directive/expression;
    • 可显示Model的数据;
    • 将数据同步到Model;
    • 可与用户交互。
  • C: Controller,即控制器,是应用程序中处理用户交互的部分,在AngularJS中:
    • 即AngularJS的Controller;
    • 可初始化Model数据;
    • 为Model添加行为方法。

MVVM模式

有另一种观点,将AngularJS视为MVVM模式。MVVM模式将“双向绑定”的思想作为核心,切断了View和Model之间的联系,View、Model完全通过ViewModel进行交互,而且Model和ViewModel之间的交互是双向的,因此视图的数据变化会同时引起数据源数据的变化,数据源数据的变化也会立即反映到视图上。MVVM模式和MVC模式最大的区别是:模型中的数据一旦变化,会自动影响视图,不需要控制器协调。

  • M: Model, 即数据模型, 在AngularJS中:
    • 为scope中的各个数据对象;
  • V: View, 即视图, 在AngularJS中:
    • 为HTML页面;
  • VM: ViewModel, 即视图模型, 在AngularJS中:
    • 为scope对象;
  • 在AngularJS中controller不再是架构的核心,在MVVM中只是起辅助作用,用来辅助$scope对象,即VM层。

指令

所谓的指令就是AngularJS对HTML的更改、补丁,其中ng是AngularJS的简写,也是内置指令的标记。

ng-app

  • 表示AngularJS操作的范围;

  • 一个页面上仅能出现一个ng-app指令,若有多个ng-app指令,则后续的ng-app不工作;

  • ng-app若加在html标签上,则表示AngularJS控制了全页面,AngularJS会等待ng-app指令标签中的所有东西都加载后再执行,所以AngularJS的JavaScript文件在head或者body导入均可。

<!DOCTYPE html>
<html ng-app>
<head>
	<title>hello world</title>
	<meta charset="utf-8"/>
	<script type="text/javascript" src="js/lib/angularjs/angular.min.js"></script>
</head>
<body>
    {{ 1 + 2 }}
</body>
</html>

ng-init

用于声明变量,该指令的属性值可声明一个或者多个变量,多个变量直接用逗号隔开即可。

<div ng-init="num=5">
    {{num * num}}
</div>

ng-bind

将表达式的值绑定到HTML元素上(如<span../>,<div../>等)。

<p ng-bind="2 * 5"></p>

ng-style

表示给HTML元素加上样式,常见有如下三种写法。

写法一:

<div ng-style="{background:red;}"></div>

写法二:

//...
myapp.controller("MainCtrl", [function(){
    this.style = {background:red;};
}]);
//...
<body ng-controller="MainCtrl as mainctrl">
    <div ng-style="mainctrl.style"></div>
</body>

写法三:

//...
myapp.controller("MainCtrl", [function(){
    this.getStyle = function{
        return {background:red;};
    };
}]);
//...
<body ng-controller="MainCtrl as mainctrl">
    <div ng-style="mainctrl.getStyle()"></div>
</body>

注意:如果控制器中的某一个值由其他值决定,并且希望其他值改变的时候,这个值也能改变,此时要写成函数return的形式。

ng-repeat

表示重复一个HTML标签。

语法格式为:

<div ng-repeat="变量名 in 数组数据"></div>  //变量将自动按顺序迭代数组数据中的每一项。

ng-options

ng-options可以智能地从控制器中取值当做选项。注意,使用ng-options的下拉菜单必须有ng-model属性与控制器双向绑定。

在下面select代码块中实现了下拉菜单的功能,option标签实现了下拉项,页面显示的是诸如“满意”之类的文字,存入数据库的是诸如“10”之类的value值。

<select name="" id="">
    <option value="10">非常满意</option>
    <option value="8">比较满意</option>
    <option value="6">满意</option>
    <option value="4">比较不满意</option>
    <option value="2">稍微不满意</option>
    <option value="0">非常不满意</option>
</select>

ng-options常见的几种使用情形:

  • 普通数组,语法格式:label for value in array,value是提交的值,label是显示的值。

    <body ng-controller="MainCtrl as mainctrl">
        <select ng-model="mainctrl.label" ng-options="item for item in mainctrl.arr">
        </select>
        <script type="text/javascript">
        	var app = angular.module('myapp', []);
        	app.controller('MainCtrl', [function(){
        		this.label = "东风";
        		this.arr = ["东风", "幺鸡", "二饼", "二条"];
        	}])
        </script>
    </body>
    
  • 对象作为数组元素,语法格式:value as label for item in array,value是提交的值,label是显示的值。

    <body ng-controller="MainCtrl as mainctrl">
        <select ng-model="mainctrl.value" ng-options="item.id as item.city for item in mainctrl.arr">
        </select>
        <script type="text/javascript">
        	var app = angular.module('myapp', []);
        	app.controller('MainCtrl', [function(){
        		this.value = "";
        		this.arr = [
        		{"id": "010", "city": "北京"},
        		{"id": "029", "city": "西安"},
        		{"id": "0311", "city": "石家庄"},
        		{"id": "0312", "city": "保定"}];
        	}])
        </script>
    </body>
    
  • 普通对象,语法格式value as label for (label, value) in array,value是提交的值,label是显示的值。

    <body ng-controller="MainCtrl as mainctrl">
        <select ng-model="mainctrl.value" ng-options="value as key for (key, value) in mainctrl.arr">
        </select>
        <script type="text/javascript">
        	var app = angular.module('myapp', []);
        	app.controller('MainCtrl', [function(){
        		this.value = "";
        		this.arr = {
        		"广东":"粤",
        		"福建":"闽",
        		"江西":"赣",
        		"山东":"鲁",
        		"河北":"冀"
        	}
        }])
        </script>
    </body>
    

表达式

{{}}是AngularJS的表达式模板定位符,主要用于在HTML页面上产生输出,里面可以填写AngularJS的表达式,表达式只能是简单运算,包括加、减、乘、除、求模、三目运算等,但不能是函数、循环、判断、赋值等复杂语句。

模块

AngularJS的模块加载分为两种情况。

  • 匿名模块

    就是没有为ng-app指定属性值或属性值为空字符串),此时AngularJS可以自动加载并创建AngularJS模块。

  • 命名模块

    为 ng-app 指定了属性值,该属性值就是该模块的名称),此时必须调用angular对象的module()方法来创建AngularJS模块。

控制器

  • AngularJS使用装饰者模式创建控制器,即首先创建一个对象,然后不断丰富对象的内容;

  • 控制器是一个对象,是我们View与Model之间的桥梁;

  • 当我们使用了ng-controller指令, 内部就会创建控制器对象;

  • 每定义一个ng-controller指令, 内部就会创建一个新的作用域对象($scope), 并自动注入构造函数中,在函数内部可以直接使用$scope对象;

  • jQuery向外暴露了"$"这个底层变量;underscore向外暴露了"_"这个底层变量;AngularJS向外暴露了"angular"这个底层变量。

<!DOCTYPE html>
<html ng-app="myapp">
<head>
	<title>Angular程序</title>
	<meta charset="utf-8"/>
	<script type="text/javascript" src="js/lib/angularjs/angular.min.js"></script>
</head>
<body>
    <!-- 实例化控制器MainCtrl类,并起一个别名mainctrl,控制器接管的范围为此div区域。 -->
    <div ng-controller="MainCtrl as mainctrl">
    	<h1>{{mainctrl.a}}</h1>
    	<input type="button" value="点击" ng-click="mainctrl.add()">
    </div>
    <script type="text/javascript">
        //创建一个名为app的模块,第一个参数是ng-app的名称,第二个参数是一个数组,数组里存储该模块所需的依赖。
    	var app = angular.module('myapp', []);
    	//创建一个名为MainCtrl的控制器类,第一个参数是控制器的名称,第二个参数是一个数组,描述依赖项和顺序注入到函数里面用的,数组最后一个元素是控制器的函数主程序。
    	app.controller('MainCtrl', [function(){
    		//定义一个变量a并赋值100。
    		this.a = 100;
    		//做个备份。
    		var self = this;
            //定义一个方法。
    		this.add = function(){
    			//每运行一次自增1。
                self.a++;
    		}
    	}]);
    </script>
</body>
</html>

数据绑定

AngularJS只关心数据,数据的变化会自动引起视图的变化,并且视图是局部刷新,不是整个页面刷新,AngularJS会自动识别哪里用到了这个更新的数据,这个过程叫做脏检查。

数据绑定

数据从一个地方A转移(传递)到另一个地方B的过程称为数据绑定, 这个过程由框架来完成。

  • View-->Model;
  • Model-->View。

双向数据绑定

数据可以从View(视图层)流向Model(模型), 也可以从Model流向View。

  • Model<-->View:
    • 当改变View中的数据, Model对象的对应属性也会随之改变: ng-model指令 数据从View==>Model;
    • 当Model域对象的属性发生改变时, 页面对应数据随之更新: {{}}表达式 数据从Model==>View。
  • ng-model是双向数据绑定, 而{{}}是单向数据绑定。
<!DOCTYPE html>
<html ng-app="myapp">
<head>
	<title>双向绑定</title>
	<meta charset="utf-8"/>
	<script type="text/javascript" src="js/lib/angularjs/angular.min.js"></script>
</head>
<body>
    <div ng-controller="MainCtrl as mainctrl">
    	{{mainctrl.a}}
    	<br/><input type="text" ng-model="mainctrl.a">
    </div>
    <script type="text/javascript">
    	var app = angular.module('myapp', []);
    	app.controller('MainCtrl', [function(){
    		this.a = 100;
    	}])
    </script>
</body>
</html>

单向数据绑定

数据只能单方向流动。

  • View-->Model : ng-init;
  • Model-->View : {{name}};
  • ng-init用来初始化当前的作用域变量。

依赖注入

依赖对象:完成某个特定的功能需要某个对象才能实现,这个对象就是依赖对象。

依赖注入:依赖的对象以形参的形式被注入进来使用,这种方式就是依赖注入。

<script type="text/javascript">
    function(event) {
        alert(event.clientX);
    }
</script>

上图所示代码块中,event对象就是以依赖注入的方式进来使用的依赖对象。

AngularJS的 ‘$scope’对象就是依赖对象,并且是依赖注入的形式进行使用,这其中形参必须是特定的名称(‘$scope’), 否则AngularJS无法注入,将抛出异常。

<script type="text/javascript">
  function MyController($scope) {
  }
</script>

AngularJS中如果要发出Ajax请求,此时需要使用内置$http服务,所有的内置服务都是$开头的,使用依赖注入的语法引入到控制器中。

<script type="text/javascript">
    var app = angular.module('myapp', []);
    app.controller('MainCtrl', ["$http", function($http){}]);
</script>

声明式编程和命令式编程

命令式编程

命令“机器”如何去作事情(how),这样无论你想要的是什么(what),它都会按照你的命令实现,更注重执行的过程,可类比为解答题。

var arr = [1,2,3,4,5];
var newArr = [];
for(var i=0;i<arr.length;i++){
  var num = arr[i]*2;
  newArr.push(num);
}
console.log(newArr);

声明式编程

告诉“机器”你想要的是什么(what),让机器想出如何去作(how) ,更注重执行的结果,可类比为填空题。

var newArr2 = arr.map(function (item) {
  return item*2;
});
console.log(newArr2);

案例集锦

调色板

通过滑块和文本框改变色块颜色。

<!DOCTYPE html>
<html ng-app="myapp">
<head>
    <title>调色板</title>
    <meta charset="utf-8"/>
    <style type="text/css">
        .box{
            width:200px;
            height:200px;
            border:1px solid #333;
        }
    </style>
    <script type="text/javascript" src="js/lib/angularjs/angular.min.js"></script>
</head>
<body ng-controller="MainCtrl as mainctrl">
    <div class="box" ng-style="mainctrl.getColor()"></div>
    <p>
        r:
        <input type="range" min="0" max="255" ng-model="mainctrl.r">
        <input type="number" min="0" max="255" ng-model="mainctrl.r">
    </p>
    <p>
        g:
        <input type="range" min="0" max="255" ng-model="mainctrl.g">
        <input type="number" min="0" max="255" ng-model="mainctrl.g">
    </p>
    <p>
        b:
        <input type="range" min="0" max="255" ng-model="mainctrl.b">
        <input type="number" min="0" max="255" ng-model="mainctrl.b">
    </p>
    <p>
        a:
        <input type="range" min="0" max="1" step="0.01" ng-model="mainctrl.a">
        <input type="number" min="0" max="1" step="0.01" ng-model="mainctrl.a">
    </p>  
    <script type="text/javascript">
        var app = angular.module("myapp", []);
        app.controller('MainCtrl', [function(){
            this.r = 100;
            this.g = 100;
            this.b = 100;
            this.a = 0.38;
            this.getColor = function(){
                return {"background-color":"rgb(" + this.r + "," + this.g + "," + this.b + "," + this.a + ")"};
            }
        }]);
    </script>
</body>
</html>

模拟微博发布框

限制发送字数最多为140字,并且能够实时提醒用户写了多少个字,当超过140字时,数字变红,同时发布按钮无法点击。

<!DOCTYPE html>
<html ng-app="myapp">
<head>
	<title>模拟微博发布框</title>
	<meta charset="utf-8" />
	<script type="text/javascript" src="js/lib/angularjs/angular.min.js"></script>
</head>
<body ng-controller="MainCtrl as mainctrl">
    <p>
    	<textarea cols="30" rows="10" placeholder="请输入内容" ng-model="mainctrl.txt"></textarea>
    	<span ng-style="mainctrl.getColor()">{{mainctrl.txt.length}}/140字</span>
    </p>
    <p>
    	<input type="button" value="发布" ng-disabled="mainctrl.txt.length > 140"/>
    	<input type="button" value="清空" ng-click="mainctrl.reset()" ng-disabled="mainctrl.txt.length == 0"/>
    </p>
    <script type="text/javascript">
    	var app = angular.module('myapp', []);
    	app.controller('MainCtrl', [function(){
    		this.txt = "";
    		var self = this;
    		this.getColor = function(){
                return self.txt.length >= 140 ? {"color": "red"} : {"color": "#333"};
    		};
    		this.reset = function(){
    			self.txt = "";
    		}
    	}]);
    </script>
</body>
</html>

模拟表格

<!DOCTYPE html>
<html ng-app="myapp">
<head>
	<title>模拟表格</title>
	<meta charset="utf-8" />
	<style type="text/css">
	    .table_wrap{
	    	width: 600px;
	    	margin: 0 auto;
	    }
		table, tr, td, th{
			border-bottom: 1px solid #333;
			border-collapse: collapse;
		}
		th{
			cursor: pointer;
		}
		th, td{
			width: 20%;
			line-height: 150%;
		}
		tr:nth-child(2n){
			background-color: #eee;
		}
		.form_box{
			background-color: skyblue;
			padding: 10px;
			width: 400px;
			margin-top: 10px;
		}
	</style>
	<script type="text/javascript" src="js/lib/angularjs/angular.min.js"></script>
</head>
<body ng-controller="MainCtrl as mainctrl">
    <div class="table_wrap">
    	<table>
	    	<tr>
	    		<th ng-click="mainctrl.changeSort('sid')">
	    			学号 
	    			<span ng-show="mainctrl.sortBy == 'sid'">{{mainctrl.getSortSign()}}
	    			</span>
	    		</th>
	    		<th ng-click="mainctrl.changeSort('name')">
	    			姓名 
	    			<span ng-show="mainctrl.sortBy == 'name'">{{mainctrl.getSortSign()}}
	    			</span>
	    		</th>
	    		<th ng-click="mainctrl.changeSort('Chinese')">
	    			语文成绩 
	    			<span ng-show="mainctrl.sortBy == 'Chinese'">{{mainctrl.getSortSign()}}
	    			</span>
	    		</th>
	    		<th ng-click="mainctrl.changeSort('Math')">	
	    			数学成绩 
	    			<span ng-show="mainctrl.sortBy == 'Math'">{{mainctrl.getSortSign()}}
	    			</span>
	    		</th>
	    		<th ng-click="mainctrl.changeSort('English')">
	    			英语成绩 
	    			<span ng-show="mainctrl.sortBy == 'English'">{{mainctrl.getSortSign()}}
	    			</span>
	    		</th>
	    		<th>删除</th>
	    	</tr>
	    	<tr ng-repeat="item in mainctrl.data">
	    		<td>{{item.sid}}</td>
	    		<td>{{item.name}}</td>
	    		<td>{{item.Chinese}}</td>
	    		<td>{{item.Math}}</td>
	    		<td>{{item.English}}</td>
	    		<td><input type="button" value="删除" ng-click="mainctrl.delete(item.sid)"></td>
	    	</tr>
        </table>
    </div>
    <div class="form_box">  
    	<p>
    		学号:<input type="text" ng-model="mainctrl.form_obj.sid">
    	</p>
    	<p>
    		姓名:<input type="text" ng-model="mainctrl.form_obj.name">
    	</p>
    	<p>
    		语文:<input type="text" ng-model="mainctrl.form_obj.Chinese">
    	</p>
    	<p>
    		数学:<input type="text" ng-model="mainctrl.form_obj.Math">
    	</p>
    	<p>
    		英语:<input type="text" ng-model="mainctrl.form_obj.English">
    	</p>
    	<p>
    		<input type="button" value="插入" ng-click="mainctrl.add()">
    	</p>
    </div>
    <script type="text/javascript">
    	var app = angular.module('myapp', []);
    	app.controller('MainCtrl', [function(){
    		this.data = [
    		    {"sid":1002, "name":"小黎", "Chinese":102, "Math":134, "English":109},
    		    {"sid":1003, "name":"小东", "Chinese":112, "Math":114, "English":112},
    		    {"sid":1004, "name":"小董", "Chinese":132, "Math":105, "English":111},
    		    {"sid":1005, "name":"小烈", "Chinese":92, "Math":134, "English":144},
    		]
    		//表单对象,供双向数据绑定用的。AngularJS不能碰DOM,它改变的是数据,数据变化了,DOM自动变化。
    		this.form_obj = {};
    		//数据备份。
    		var self = this;
    		//增加
    		this.add = function(){
    			self.data.push(self.form_obj);
    			self.form_obj = {};
    		};
            //删除
    		this.delete = function(sid){
                for(var i = 0; i < self.data.length; i++){
                	if(self.data[i].sid == sid){
                		self.data.splice(i, 1);
                	}
                }
    		};
    		//按谁排序
    		this.sortBy = "sid";
    		//升序还是降序,true表示升序
    		this.asc = true;
            
    		this.getSortSign = function(){
                 return self.asc ? "▼" : "▲";
    		};
            //排序
            this.changeSort = function(key_name){
            	if(key_name == self.sortBy){
            		self.asc = !self.asc;
            	}else{
                    self.sortBy = key_name;
                    self.asc = true;
            	}
            	self.data.sort(function(a, b){
            		if(a[self.sortBy] > b[self.sortBy]){
            			return self.asc ? 1 : -1;
            		}else{
            			return self.asc ? -1 : 1;
            		}
            	})
            };
    	}]);
    </script>
</body>
</html>

表单验证

两个条件

  • 需要验证的控件必须有ng-model属性;
  • form必须有name属性。

要想验证表单,必须符合上面两个条件;只要符合上面两个条件,表单就开始验证了。

<body ng-controller="MainCtrl as mainctrl">
    <form name="myform">
    	<p>
    		姓名:<input type="text" required ng-model="mainctrl.formobj.name">
    	</p>
    </form>
    <script type="text/javascript">
    	var app = angular.module('myapp', []);
    	app.controller('MainCtrl', [function(){
    		this.formobj = {};
    	}])
    </script>
</body>
<!DOCTYPE html>
<html ng-app="myapp">
  <head>
    <title>表单验证</title>
    <meta charset="utf-8" />
    <style type="text/css">
      body {
        font-size: 16px;
        font-family: "微软雅黑";
      }
      span {
        font-size: 12px;
      }
      .passwordstrengthbar {
        width: 100px;
        height: 20px;
      }
      .s1 {
        background-color: red;
      }
      .s2 {
        background-color: orange;
      }
      .s3 {
        background-color: yellow;
      }
      .s4 {
        background-color: lightseagreen;
      }
      .s5 {
        background-color: green;
      }
    </style>
    <script
      type="text/javascript"
      src="js/lib/angularjs/angular.min.js"
    ></script>
  </head>
  <body ng-controller="MainCtrl as mainctrl">
    {{mainctrl.formobj}}
    <form name="myform">
      <p>
        *姓名:<input
          type="text"
          required
          name="name"
          ng-model="mainctrl.formobj.name"
          ng-pattern="/^([\u4e00-\u9fa5]{2,20}|[a-zA-Z.\s]{2,20})$/"
        />
        <span ng-show="myform.name.$dirty && myform.name.$error.required"
          >请填写用户名</span
        >
        <span ng-show="myform.name.$error.pattern">不合法的姓名</span>
      </p>
      <p>
        *年龄:
        <input
          type="number"
          name="age"
          required
          ng-model="mainctrl.formobj.age"
          min="7"
          max="18"
        />
        <span ng-show="myform.age.$dirty && myform.age.$error.required"
          >请填写年龄</span
        >
        <span ng-show="myform.age.$error.max">最大为18岁</span>
        <span ng-show="myform.age.$error.min">最小为7岁</span>
      </p>
      <p>
        *密码:
        <input
          type="password"
          name="password"
          required
          ng-model="mainctrl.formobj.password"
          ng-minlength="6"
        />
        <span
          ng-show="myform.password.$dirty && myform.password.$error.required"
          >请填写密码</span
        >
        <span ng-show="myform.password.$error.minlength">最短长度6位</span>
        <span ng-show="mainctrl.passwordScore < 3">密码强度不够</span>
      </p>
      <p
        class="passwordstrengthbar"
        class="s5"
        ng-class="mainctrl.getStrengthClass()"
        ng-show="myform.password.$valid"
      >
        {{mainctrl.passwordtip}}
      </p>
      <p>
        网址:
        <input type="url" name="url" ng-model="mainctrl.formobj.url" />
        <span ng-show="myform.url.$error.url">网址格式不正确</span>
      </p>
      <p>
        <input
          type="button"
          value="提交"
          ng-disabled="myform.$invalid || mainctrl.passwordScore < 3"
        />
      </p>
    </form>
    <script type="text/javascript">
      var app = angular.module("myapp", []);
      function checkStrength(password) {
        var lv = 0;
        if (!password) {
          return;
        }
        if (password.match(/[a-z]/g)) {
          lv++;
        }
        if (password.match(/[0-9]/g)) {
          lv++;
        }
        if (password.match(/([A-Z])/g)) {
          lv++;
        }
        if (password.match(/([\!\@\#\$\%\^\&\*\?\/\|\\])/g)) {
          lv += 2;
        }
        if (password.length < 6) {
          lv = 0;
        }
        if (lv > 5) {
          lv = 5;
        }
        return lv;
      }
      app.controller("MainCtrl", [
        function () {
          this.formobj = {};
          this.passwordtip = "";
          this.getStrengthClass = function () {
            this.passwordScore = checkStrength(this.formobj.password);
            console.log(this.passwordScore);
            if (this.passwordScore == 1) {
              this.passwordtip = "不安全";
            } else if (this.passwordScore == 2) {
              this.passwordtip = "较不安全";
            } else if (this.passwordScore == 3) {
              this.passwordtip = "安全";
            } else if (this.passwordScore == 4) {
              this.passwordtip = "较安全";
            } else if (this.passwordScore == 5) {
              this.passwordtip = "特别安全";
            }
            return "s" + this.passwordScore;
          };
        },
      ]);
    </script>
  </body>
</html>

热门相关:帝少的专属:小甜心,太缠人   寂静王冠   致灿烂的你   第一神算:纨绔大小姐   霸皇纪