angularjs 控制器、做用域、广播详解

1、控制器javascript

首先列出几种咱们日常使用控制器时的几种误区:css

咱们知道angualrJs中一个控制器时能够对应不一样的视图模板的,但这种实现方式存在的问题是:html

若是视图1和视图2根本没有任何逻辑关系,这样“控制器”的角色就会很尴尬,由于咱们不可能把不一样业务的数据模型都绑在同一个控制器中。java

 

这种实现方式也存在一个问题是:若是控制器1和控制器2里面有2个方法是如出一辙的怎么办?angularjs

 

<!doctype html>
<html ng-app>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <div ng-controller="CommonController">
            <div ng-controller="Controller1">
                <p>{{greeting.text}},Angular</p>
                <button ng-click="test1()">test1</button>
            </div>
            <div ng-controller="Controller2">
                <p>{{greeting.text}},Angular</p>
                <button ng-click="test2()">test2</button>
                <button ng-click="commonFn()">通用</button>
            </div>
        </div>
    </body>
    <script src="js/angular-1.3.0.js"></script>
    <script src="MVC3.js"></script>
</html>
function CommonController($scope){
    $scope.commonFn=function(){
        alert("这里是通用功能!");
    };
}

function Controller1($scope) {
    $scope.greeting = {
        text: 'Hello1'
    };
    $scope.test1=function(){
        alert("test1");
    };
}

function Controller2($scope) {
    $scope.greeting = {
        text: 'Hello2'
    };
    $scope.test2=function(){
        alert("test2");
    }
}

虽然子级控制器能够继承父级控制器的做用域及方法,可是咱们通常不要去这样作,由于极可能会形成做用域的混乱。浏览器

 

正确的方式应该是这样的:咱们把公共的方法抽离出来,放在公共的服务当中去,须要的时候从公共的服务中调取就行了。app

 

在使用控制器时要注意几点:工具

1.不要去复用controller,一个控制器通常只负责一小块视图;(通常控制器处理的都是业务逻辑,业务逻辑的复用性通常很小)spa

2.不要在controller中操做DOM,这不是控制器的职责;(由于在 controller里面操做DOM会致使浏览器页面的重绘,这种代价是昂贵的)3d

3.通常不要在控制器里面作数据过滤操做,ng有$filter服务;

通常来讲,Controller是不会相互调用的,控制器之间的交互会经过广播事件进行!

 

2、做用域

angularJs的MVC是借助$scope来实现的!

先来看一段代码:

<!doctype html>
<html ng-app>
    <head>
        <meta charset="utf-8">
        <link rel="stylesheet" type="text/css" href="Scope1.css" />
    </head>
    <body>
        <div class="show-scope-demo">
            <div ng-controller="GreetCtrl">
                Hello {{name}}!
            </div>
            <div ng-controller="ListCtrl">
                <ol>
                    <li ng-repeat="name in names">
                        {{name}} from {{department}}
                    </li>
                </ol>
            </div>
        </div>
    </body>
    <script src="js/angular-1.3.0.js"></script>
    <script src="Scope1.js"></script>
</html>
function GreetCtrl($scope, $rootScope) {
    $scope.name = 'World';
    $rootScope.department = 'Angular';
}

function ListCtrl($scope) {
    $scope.names = ['Igor', 'Misko', 'Vojta'];
}

上面是两个不一样的控制器,尽管ListCtrl控制器里面没有department,但它依然能够访问到department上的变量值。

 

神奇的$scope

1.$scope是一个对象;

2.$scope是表达式的执行环境(或者叫作做用域)(它是视图和控制器之间的胶水);

3.$scope提供了一些工具方法$watch()/$apply();  

(这个是实时检测对象属性变化的,在修改数据时会马上更新$scope,当$scope发生变化时会马上从新渲染视图);

(这两个方法虽然提供了监视数据模型变化的能力,将数据模型的变化在整个应用范围内进行通知,但通常咱们不太会手动去调用$scope.$apply())

4.$scope是一个树形结构,与DOM标签平行;

5.子$scope会继承父$scope上的属性和方法;

6.每一个angularJs应用只有一个$rootScope,通常位于ng-app上,$rootScope是全部$scope的最上层,

($rootScope也是angularJs中最接近全局做用域的对象,在$rootScope上附加太多业务逻辑并非好主意,这与污染javaScript的全局做用域是同样的)

7.$scope也是实现双向数据绑定的基础;

8.能够用angular.element($0).scope()来进行调试;

9.$scope能够在控制器之间传播事件,能够向上$scope.$emit();也能够向下$scooe.$broadcast();

最后附一张$scope的生命周期图:

建立(建立一个做用域)——连接($scope对象会连接到视图中)——更新(脏值检查)——销毁(销毁做用域)

 

3、广播

3.1相关概念

一般做用域之间是不共享变量的,但做用域是有层次的,因此咱们能够在做用域上经过广播来传递事件。

Angularjs中不一样做用域之间能够经过组合使用$emit,$broadcast,,$on的事件广播机制来进行通讯

$emit的做用是将事件从子级做用域传播至父级做用域,包括本身,直至根做用域。格式以下:$emit(eventName,args)

$broadcast的做用是将事件从父级做用域传播至子级做用域,包括本身。格式以下:$broadcast(eventName,args)

$on用于在做用域中监控从子级或父级做用域中传播的事件以及相应的数据。格式以下:$on(event,data)

上述说明中,eventName是须要广播的事件的名称,args传递的数据集合,$on 方法中的参数event是事件的相关对象,data是事件传播的数据。

 

3.2实例说明angularjs  $emit $broadcast $on的用法

<div ng-controller="ParentCtrl">
    <div ng-controller="SelfCtrl">
        <a ng-click="click()">click</a>
        <div ng-controller="ChildCtrl"></div>
    </div>
    <div ng-controller="BroCtrl"></div>
</div>
var appControllers = angular.module('myApp', [])
appControllers.controller('SelfCtrl', ['$scope','$rootScope', function($scope, $rootScope){
        var admin1 = {
            'name': 'father',
            'age': 45
        };
        var admin2 = {
            'name': 'Lucy',
            'age': 25
        };
        $scope.click = function() {
            //事件的发送
            //向子级控制器传递数据和事件,只有ChildCtrl能接受到广播,还有本身
            $scope.$broadcast('to-child', admin2);
            //向父级控制器传递数据和事件,只有parentCtrl能接收到广播,还有本身
            $scope.$emit('to-parent', admin1);
            //$rootScope发出的广播全部的做用域均可以接受到,能够用于同级之间进行广播
            $rootScope.$broadcast('to-bro', '平级的数据');
        }
    }])
appControllers.controller('ParentCtrl', ['$scope', '$rootScope', function($scope, $rootScope){ //事件的接受 $scope.$on('to-parent', function(event, data){ console.log(event); }); }])
appControllers.controller('ChildCtrl', ['$scope', '$rootScope', function($scope, $rootScope){ $scope.$on('to-child', function(event, data){ console.log(data); }); }])
appControllers.controller('BroCtrl', ['$scope', '$rootScope', function($scope, $rootScope){ //$scope和$rootScope均可以接受到事件 $scope.$on('to-bro', function(event, data){ console.log(data); }); $rootScope.$on('to-bro', function(event, data){ console.log(data); }); }]);
相关文章
相关标签/搜索