AngularJs MVC的设计思想以及实现原理

AngularJs MVC #

模型 – 视图 – 控制器或MVC,MVC是普遍的叫法,是一种软件设计模式,用于开发Web应用程序。模型- 视图 – 控制器模式是由以下三部分组成:

  • 模型/Model – 一个负责维护数据模式的最低水平,模型是负责管理应用程序的数据。它响应来自视图的请求,同时也响应指令从控制器进行自我更新。

  • 视图/View – 负责显示所有或数据到用户的部分,在一个特定的格式的演示数据,由控制器决定触发显示数据。它们是基于脚本的模板系统,如JSP,ASP,PHP,非常容易使用AJAX技术的集成。

  • 控制器/Controller – 软件代码控制Model和View之间的相互作用,控制器负责响应于用户输入并执行交互数据模型对象。控制器接收到输入,它验证输入,然后执行修改数据模型的状态的业务操作。

    AngularJS是一个MVC框架。在接下来的章节中,让我们看到了AngularJS如何使用MVC方法。

比较很有名的前端MVC框架:ExtJs

看看angular

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="css/foundation.min.css">
</head>
<body style="padding:10px;" ng-app="app">
<div ng-controller="MyCtrol">
    <input type="text" ng-model="msg">
    <h1>{{msg}}</h1>
</div>
</body>
<script src="js/angular.min.js"></script>
<script src="js/myCtrol.js"></script>
<!--
MyCtrol:就是C
$scope:就是M
div:就是V
-->
</html>

看看ng-bind

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="css/foundation.min.css">
</head>
<body style="padding:10px;" ng-app="">
<div>
    <input type="text" ng-model="msg">
    <h1 ng-clock class="ng-clock">{{msg}}</h1>
    <!--ng-clock的作用就是,在完全渲染之前不会让{{}}显示-->
    <h1 ng-bind="msg"></h1>
    <div class="{{msg}}">{{msg}}</div>
</div>
</body>
<script src="js/angular.min.js"></script>
</html>

~~~

1.模块化 #

1.1 创建模块 #

一切从模块开始

angular.module(name, [requires], [configFn]);

1.1.1 模块的名字 #

name:字符串类型,代表模块的名称;

1.1.2 依赖的模块 #

requires:字符串的数组,代表该模块依赖的其他模块列表,如果不依赖其他模块,用空数组即可

1.1.3 模块的配置 #

configFn:用来对该模块进行一些配置。

2.控制器 #

2.1 创建控制器 #

通过模块创建控制器

angular.module('appModule').controller('appCtrl',function(){});

2.2 使用控制器 #

<div ng-controller="ctrl"></div>

2.2 控制器中的$scope #

angular.module('appModule').controller('appCtrl',function($scope){});

当前作用域$scope,$scope就是viewModel

2.3 控制器特点 #

  1. controller和DOM平行
  2. 控制器可以声明变量和方法
  3. 控制器可以嵌套
  4. 子控制器可以继承父控制器

2.4 控制器的合理使用 #

  1. 不要复用controller
  2. 不要在controller中操作DOM
  3. 不要再controller里格式化数据
  4. 控制器之间交互是通过事件进行的

3.$scope和$rootScope #

3.1 注入$scope和$rootScope #

我们想使用$scope和$rootScope可以注入进来(名字是固定的)

angular.module('appModule').controller('appCtrl',function($scope,$rootScope){});

3.2 初始化方法 #

通常情况下我们会将$rootScope上的代码提取声明

app.run(function($rootScope){});

3.3 防止代码压缩 #

通过压缩工具压缩代码后$scope等名称改变报错

app.controller('appCtrl',['$scope',function ($s) {
    $s.name = 'zfpx';
}]);
md.run(["$rootScope",function($s){
    $s.name = 'zfpx';
}]);

4.$watch和$apply #

4.1 $watch监听模型上的值 #

页面代码

<div ng-controller="appCtrl">
+    <input type="text" ng-model="name">
</div>

4.1.1 监听写法1: #

app.controller('appCtrl',['$scope',function ($s) {
+        $s.$watch('name', function (newVal,oldVal) {
+            console.log(newVal,oldVal);
+        })
}]);

4.1.2 监听写法2: #

app.controller('appCtrl',['$scope',function ($s) {
       $s.$watch(function () {
           return $s.name;
       }, function (newVal,oldVal) {
           console.log(newVal,oldVal);
       });
}]);

4.2 $watch监听方法 #

页面代码

<div ng-controller="appCtrl">
    <input type="text" ng-model="val1">
    +
    <input type="text" ng-model="val2">
    {{total()}}
</div>

控制器

app.controller('appCtrl',['$scope',function ($s) {
        $s.total = function () {
            return $s.val1+$s.val2;
        };
        $s.$watch($s.total, function (newVal,oldVal) {
            console.log(newVal,oldVal);
        })
}]);

4.3 $apply刷新视图 #

4.3.1 原生的方法不会刷新视图 #

页面代码

<div ng-controller="appCtrl">
    {{name}}
</div>

控制器

app.controller('appCtrl',['$scope',function ($s) {
        $s.name = 1;
        setInterval(function () {
            $s.name++
        },1000)
}]);

4.3.2 通知视图刷新 #

通知方式1:

app.controller('appCtrl',['$scope','$interval',function ($s,$interval) {
    $s.name = 1;
    setInterval(function () {
        $s.name++;
        $s.$apply();
    },1000);
}]);

通知方式2:

app.controller('appCtrl',['$scope','$interval',function ($s,$interval) {
    $s.name = 1;
    setInterval(function () {
        $s.$apply(function(){
            $s.name++;
        });
    },1000);
}]);

4.4 自带的指令会刷新视图 #

4.4.1 $timeout #

app.controller('appCtrl',['$scope','$timeout',function ($s,$timeout) {
    $s.name = 1;
    $timeout(function () {
        $s.name++;
    },1000);
}]);

4.4.2 $interval #

app.controller('appCtrl',['$scope','$interval',function ($s,$interval) {
    $s.name = 1;
    $interval(function () {
        $s.name++;
    },1000);
}]);

4.4.3 取消定时器 #

app.controller('appCtrl',['$scope','$interval',function ($s,$interval) {
    $s.name = 1;
    var timer = $interval(function () {
        $s.name++;
        $interval.cancel(timer);
    },1000);
}]);

已经是angular自带的指令就不要在调用$apply去通知了

5.ng-href #

表达式生效前不要加载该资源,防止空链接

<a ng-href="{{ myHref }}">baidu</a>
var app = angular.module('appModule',[]);
app.controller('appCtrl',function ($scope,$timeout) {
  $timeout(function () {
      $scope.myHref = 'http://www.baidu.com';
  },20000)
})

6.ng-src #

表达式生效前不引用该资源,防止出现404

<img ng-src="{{imgSrc}}"/>
var app = angular.module('appModule',[]);
app.controller('appCtrl',function ($scope,$timeout) {
    $timeout(function() {
        $scope.imgSrc = 'https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png';
    }, 1000);
});

7.控制器间的交互 #

控制器间的交互是通过事件进行监听的

<div ng-controller="parentCtrl">
    商品总价 <input type="text" ng-model="total">
    <div ng-controller="childCtrl">
        商品的名称 {{product.name}} <br>
        商品的单价 {{product.price}} <br>
        商品的数量 <input type="text" ng-model="product.count" ng-change="total()">
    </div>
</div>

子控制器代码

app.controller('childCtrl', function ($scope) {
        $scope.product = {name:'火车', price:10,count:1}
});

父控制器代码

app.controller('parentCtrl', function ($scope) {
        $scope.total = 10;
});

7.1 $emit发射事件 #

修改子控制器代码,当数量变化时通知父控制器

$scope.product = {name:'火车', price:10,count:1}
+ $scope.total = function () {
+     $scope.$emit('total',$scope.product.price*$scope.product.count);
+ };

7.2 $on监听子控制器事件 #

监听子控制器发射的事件

$scope.total = 10;
+ $scope.$on('total', function (ev,data) {
+     $scope.total = data;
+ });

7.3 $broadcast向下广播 #

当总价改变,向下通知所有子控制器

+ $scope.$watch('total', function () {
+     $scope.$broadcast('count',$scope.total);
+ });

7.4 $broadcast父控制器向下广播 #

子控制器接收父控制器广播的内容

$scope.$on('count', function (ev,data) {
    $scope.product.count = data/$scope.product.price;
});

8.表单元素 #

8.1 ng-disabled #

当表单元素被设置disabled属性为true时元素不可用

<button ng-disabled='true'>点击</button>

8.2 ng-readonly #

当表单元素被设置readonly属性为true时元素仅读

<input type="text" ng-readonly="true" value="仅读"/>

8.3 select循环数据 #

用id的值作为value,以name值作为可见参数去数据中遍历

<select ng-model="name" ng-options="t.id as t.name for t in type"></select>

定义select中的数据

app.controller('appCtrl',['$scope','$interval',function ($s,$interval) {
        $s.type = [{name:'人类',id:1},{name:'动物',id:2},{name:'动物',id:3}]
}]);

9.模块间的依赖 #

创建第一个模块

var app = angular.module('appModule1',[]);
app.controller('appCtrl', function ($scope,$interval) {
  $scope.name = 20;
});

创建第二个模块并依赖第一个模块

var app1 = angular.module('appModule2',['appModule1']);
app1.controller('appCtrl', function ($scope,$interval) {
  $scope.name = 1;
});

被依赖的同名控制器会被覆盖掉

10.启动多个模块 #

将不同的模块应用到不同的div上,达到启动多个ng-app的效果

<div ng-controller="appCtrl" id="div1">{{name}}</div>
<div ng-controller="appCtrl" id="div2">{{name}}</div>
var app1 = angular.module('appModule2',[]);
app1.controller('appCtrl', function ($scope,$interval) {
    $scope.name = 'zfpx';
});
var app = angular.module('appModule1',[]);
app.controller('appCtrl', function ($scope,$interval) {
    $scope.name = 'home';
});
angular.bootstrap(div1,['appModule1']);
angular.bootstrap(div2,['appModule2']);

~~~

angularjs 中只能有一个模块module(ng-app=””),一个模块可以有多个控制器(ng-controller=””)

angularJS中的多模块开发是指多个module模块开发,步骤为:

  1. 确定主模块    var app=angular.module(‘myApp’,[]);

  2. 其他的子模块添加到主模块后面的中括号中

    var app=angular.module(‘myApp’,[‘myApp1′,’myApp2’]);

  3. 创建子模块 var app1=angular.module(‘myApp1’,[]);

  注意:子模块所在的标签必须写在主模块标签的内部

不太推荐的多模块开发:

  1. 在标签内设置id

  2. 通过  angular.bootstrap(document.getElementById(“myApp1”),[“myApp1”]); 给标签设置成模块。

  angular.bootstrap()的第一个参数是获取的dom元素,第二个参数是要设置的模块名称,注意,该项以数组形式填写。

模块是提供一些特殊服务的功能块,比如本地化模块负责文字本地化,验证模块负责数据验证。一般来说,服务在模块内部,当我们需要某个服务的时候,是先把模块实例化,然后再调用模块的方法。但Angular模块和我们通常理解的模块不一样,Angular模块只保留服务的声明,服务的实例化是由服务注入器完成的,实例化之后服务就留在了服务注入器中,和模块没有关系了,这就是为什么我们使用的服务全部来自注入器的原因。

每调用一次angular.boostrap()方法会创建一个新的Angular应用和一个新的服务注入器,因此,每个应用都对应一个服务注入器,彼此互不冲突。

在angular中,模块可以是对象、方法(如果是数组,数组的最后一个元素必须是方法,前面的元素都是方法按顺序排列的参数名称)。后面讲的模块属性和方法,都属于通过angular.module()定义的模块对象。如果模块是方法,是不需要经过angular.module()定义的,只需写入依赖数组(就是说依赖数组的元素可以是方法),模块在加载依赖关系的时候直接执行了。

注意:通过angular.module()方法定义的模块是唯一的,如果重复定义就会覆盖前面的定义。

ng

angular.module(‘ng’,[‘ngLocale’]).config([‘$provide’, function(){}]);

结果是configBlocks.push([‘$injector’, ‘invoke’,[‘$provide’, function(){}]])。

三个固定模块

每个使用bootstrap(element, modules, config)生成的应用,注入器中有三个固定的模块:

  • 第一个模块是”ng”。
  • 第二个模块是[‘$provider’,fn],它的作用是把根元素element作为变量保存在$provider中。
  • 第三个模块是[‘$compileProvider’,fn],它的作用是根据config.debugInfoEnabled调用 $conpileProvider.debugInfoEnabled(true)。

未经允许不得转载:WEB前端开发 » AngularJs MVC的设计思想以及实现原理

赞 (0)