AngualrJS学习记录-作用域的层级和事件

本文深入探讨AngularJS中作用域层级的概念及其如何通过事件进行数据通信,详细解析作用域间的层次结构、数据传递机制以及事件传播的应用场景。

AngualrJS学习记录-作用域的层级和事件

与DOM模型相似,作用域在绑定页面元素后,便依据元素的层次关系形成了自身的层级关系,而在这些层级关系中,它们还可以通过事件的传播进行数据的通信,只是这种通过事件的数据通信应用的场景非常有限,仅限与父和子之间的作用域通信。

  • 作用域的层级
    与DOM树状结构类似,作用域也拥有自己的层级,并且与DOM的树状结构相辅相成,它的顶级作用域只有一个,而下面的子级作用域可以创建多个,子级作用域可以继承父级作用域中的全部属性和方法,但子级作用域之间却不能互相访问各自的属性和方法。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script src="../js/angular.min.js"></script>
    <style>
        body{
            font-size:12px;
        }
        ul{
            list-style-type: none;
            width:408px;
            margin:10px 0;
            padding:0;
        }
        ul .ng-scope{
            background-color:#eee;
        }
        ul li{
            float: left;
            padding:5px 0;
        }
        ul .bold{
            font-weight:bold;
        }
        ul .school{
            float:right;
            margin-right:80px;
        }
        ul li span{
            width:52px;
            float: left;
            padding:0 10px;
        }
    </style>
</head>
<body ng-app="app" ng-controller="myCtr">

    <ul ng-controller="myCtr2">
        <li ng-class="{{school}}">{{s_name}}{{c_name}}</li>
        <li ng-class="{{bold}}">
            <span>序号</span>
            <span>姓名</span>
            <span>学号</span>
            <span>英文</span>
            <span>数学</span>
        </li>
        <li ng-repeat="stu in data">
            <span>{{$index + 1}}</span>
            <span>{{stu.name}}</span>
            <span>{{stu.sex}}</span>
            <span>{{stu.english}}</span>
            <span>{{stu.maths}}</span>
        </li>
    </ul>
    <ul ng-controller="myCtr3">
        <li ng-class="{{school}}">{{s_name}}{{c_name}}</li>
        <li ng-class="{{bold}}">
            <span>序号</span>
            <span>姓名</span>
            <span>学号</span>
            <span>英文</span>
            <span>数学</span>
        </li>
        <li ng-repeat="stu in data">
            <span>{{$index + 1}}</span>
            <span>{{stu.name}}</span>
            <span>{{stu.sex}}</span>
            <span>{{stu.english}}</span>
            <span>{{stu.maths}}</span>
        </li>
    </ul>

</body>
<script>
     var app = angular.module('app',[]);

     //父级作用域
     app.controller('myCtr',['$scope',function($scope){

         $scope.s_name = "广州市第四中学";
         $scope.bold = 'bold';
         $scope.school = 'school';

     }]);

    //子级作用域
    app.controller('myCtr2',['$scope',function($scope){

        $scope.c_name = "初一(2)班";
        $scope.data = [
            {name : '赵东',sex : '男',english : '88',maths : 95},
            {name : '张雷',sex : '女',english : '82',maths : 65},
            {name : '何小军',sex : '男',english : '78',maths : 78},
            {name : '林冬梅',sex : '女',english : '98',maths : 99}
        ]

    }]);

     //子级作用域
     app.controller('myCtr3',['$scope',function($scope){

         $scope.c_name = "初一(4)班";
         $scope.data = [
             {name : '李晓',sex : '男',english : '78',maths : 86},
             {name : '李明',sex : '男',english : '92',maths : 77},
             {name : '蒋栋',sex : '男',english : '85',maths : 86},
             {name : '林正红',sex : '女',english : '97',maths : 100}
         ]

     }]);





</script>


</body>
</html>

源码分析:
在例子中我们分别定义3个控制器,父级作用域中我们有一些公有属性,是可以被子级作用域访问到,并且能正确输出的,而子级作用域中分别也写上对应的私有属性,我们可以发现它们属性名相同,但互不影响,说明子级作用域中的属性是不可以被同级作用域去访问的。

如果在父级作用域中的$scope,添加了”s_name”,”bold”,”school”,然后父级作用域又在$rootScope对象中添加属性和方法,那么子级作用域将首先访问$scope对象,然后访问$rootScope对象。

在子级作用域的视图模板中,当页面渲染”s_name”属性值时,首先,它在取值阶段,将在元素本身所属的作用域中寻找是否存在该属性,如果不存在,则继续向上级作用域中查找,如果没有找到,则直接在顶级的$rootScope对象中查找,确定属性的作用域之后,再进入计算值阶段,计算后,直接将获取的值渲染在页面的元素中。

*每一个作用域都会自动添加一个类别名为”ng-scope”的css样式,因此,可以通过修改该样式,来显示各作用域所控制的范围区域。

  • 作用域事件的传播
    在Angular中,作用域间有非常清晰的层次结构关系,类似于DOM树状图形,最顶层的就是rootScope作用域,其余的都是在它基础上进行分支和嵌套。在这种关系下的作用域,它们之间的数据通信变得相对复杂,概括来说,有下列两种方式可以实现作用域的通信。

    • 服务(service)
      通过在作用域间创建一个单例的服务,由该服务来处理各个作用域间的数据通信,这种方式以后学到了在详细介绍

    • 事件(event)
      除使用服务外,还可以通过作用域间的事件进行数据通信,而要使用事件,则必须调用Angular中提供的两个方法$broadcasted$emitted,方法$broadcasted的功能是将事件从父级作用域传播至子级作用域,它的调用格式如下

$broadcast(eventname,data)

其中,参数eventname为定义的事件名称,data为事件传播过程中携带的数据信息。
方法$emitted的功能是将事件从子级作用域传播至父级作用域,它的调用格式如下“。

$emitted(eventname,data)

各参数的功能与$broadcast相同。

除了两个传播事件的方法外,还需要通过调用$on方法,在作用域中监控传播来的事件并获取相应的数据,它的调用格式如下:

$on(eventname,function(event,data){
    //接收传播事件的处理代码
})

在上面例子中,eventname为需要监控的传播事件名称,event为事件传播过程中自带的特征,该特征包括下列几个重要的属性:

  • event.targetScope : 返回发起传播事件的作用域名称
  • evnet.currentScope : 返回正在接收传播事件的作用域名称
  • evnet.name : 传播事件的名称
  • event.stopPropagation() : 防止事件进行冒泡操作的函数
  • event.preventDefault() : 阻止代码事件的发生
  • evnet.defaultPrevented : 当执行了preventDefault()方法时,该属性值为true否则为false

而在$on方法处理传播事件的函数中,另外一个data参数,则为事件在传播过中携带的数据,通过该对象可以在各个监控的作用域中获取传播时的数据,实现数据通信的功能。

虽然说通过作用域的事件可以实现数据通信的功能,但是它们的传播范围非常有限,中能是调用$broadcasted$emitted这两个方法,在父和子级的作用域间进行传播,其他不具有这种关系的作用域将无法监控到传播来的事件。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script src="../js/angular.min.js"></script>
    <style>
        body{
            font-size:12px;
        }
    </style>
</head>
<body ng-app="app">

    <div ng-controller="myCtr1">
        <div ng-controller="myCtr2">
            <button ng-click="to_parent()">向父级作用域传播</button>
            <button ng-click="to_child()">向子级作用域传播</button>
            <div ng-controller="myCtr3"></div>
        </div>
        <div ng-controller="myCtr4"></div>
    </div>

</body>
<script>
     var app = angular.module('app',[]);

     //父级作用域
     app.controller('myCtr1',['$scope',function($scope){

         $scope.$on('event_1',function(event,data){
             console.log('在父级中监听到',data);
         });

         $scope.$on('event_2',function(event,data){
             console.log('在父级中监听到',data);
         });

     }]);

    //子级作用域
    app.controller('myCtr2',['$scope',function($scope){

        $scope.to_parent = function(){

            $scope.$emit('event_1','事件来源于子级');

        };

        $scope.to_child = function(){

            $scope.$broadcast('event_2','事件来源于父级');

        };

    }]);

     //子级作用域
     app.controller('myCtr3',['$scope',function($scope){

         $scope.$on('event_1',function(event,data){
             console.log('在子级中监听到',data);
         });

         $scope.$on('event_2',function(event,data){
             console.log('在子级中监听到',data);
         });

     }]);

     //子级作用域
     app.controller('myCtr4',['$scope',function($scope){

         $scope.$on('event_1',function(event,data){
             console.log('在同级中监听到',data);
         });

         $scope.$on('event_2',function(event,data){
             console.log('在同级中监听到',data);
         });

     }]);





</script>


</body>
</html>

源码分析:
在列子中定义了多个控制器,并通过ng-controller指令将它们与页面中各个作用域相绑定,并且定了2个按钮,分别为”to_parend”和”to_child”。在”to_parend”方法中调用了$emit方法,向父级作用域传播”event_1”事件和”事件来源于子级”的字符串数据,而在”to_child”中,则调用了$broadcast方法,向子作用域传播”event_2”和”事件来源于父级”的字符串数据,在其他控制器中则通过调用$on方法来接收其他作用域传播来的事件和数据。
当点击第一个按钮向父级传播事件后,myCtr1会接收到事件的传播并打印到页面中,而点击第二个按钮向子级传播事件后,myCtr3会接收到事件的传播并打印到页面中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值