angularJs 父子作用域之间的通信—$on、 $emit、$broadcast的介绍

angularJs中的作用域($scope)结构和DOM结构非常相似,也是一个层次分明的树状结构。它有一个根作用域$rootscope(对应angular应用或ng-app),其他作用域是嵌套在根作用域下面的。


angularJs的$scope之间都遵循js中对象原型继承方式,当子作用域中没有该对象时,默认向上级作用域(父作用域)寻找,直到找到或者到达$rootscope为止,当子作用域有该对象时,使用子作用域中的对象。

注:这里的父作用域包含直接父级和祖先,子作用域包含直接子级和更下层级

例子如下:

<body ng-app="myApp">
    <div ng-controller="fatherCtrl">
        <input type="text" ng-model="name" ng-change="nameOnChange()">
        <h1>Father: {{name}}!</h1>
        <div ng-controller="sonCtrl">
             <input type="text" ng-model="name" ng-change="nameOnChange()"> 
             <h1>Son: {{name}}</h1>
        </div>
    </div>
</body>

其中fatherCtrl 和 sonCtrl 里都使用了 name,但sonCtrl中并没有定义name。

var app = angular.module ('myApp', []);
    app.controller('fatherCtrl', function ($scope) {
        $scope.name = "father";
        $scope.$watch("name",function () {
            console.log("fatherScope:"+$scope.name)
        })

    });
    app.controller('sonCtrl', function ($scope) {
        $scope.$watch("name",function () {
            console.log("sonScope:"+$scope.name)
        })
    });



这时sonCtrl 直接读取 fatherCtrl 中的 name,改变fatherCtrl中name的值,sonCtrl显示的值也会同步改变。

效果如图:






但当通过view同步改变sonCtrl中name的值时,sonCtrl中会重新创建一个name的对象,faterCtrl中的值不会改变。


效果如图:

这里写图片描述



如何在作用域之间通信呢?
1.创建一个单例服务,然后通过这个服务处理所有子作用域的通信。
2.通过作用域中的事件处理通信。但是这种方法有一些限制;你并不能广泛的将事件传播到所有监控的作用域中。你必须选择是与父级作用域或者子作用域通信。


$on、$emit和$broadcast使得event、data在controller之间的传递变的简单。
1、$emit:子传父,传递event与data;

        $scope.$emit('name', 'args');

2、$broadcast:父传子,传递event与data;

         $scope.$broadcast('name', 'args');

3、$on:监听或接收数据,用于接收event与data;

        $scope.$on('name', function(event,data){});

$broadcast、$emit事件必须依靠其他事件(ng-click等)进行触发。

值得注意的是:以上事件的主语是 $scope, 因为所有的事件其实都是作用在scope上的。

在$on的方法中的event事件参数,其对象的属性和方法如下:

事件属性/方法功能性说明
event.targetScope获取传播事件的作用域
event.currentScope获取接收事件的作用域
event.name传播的事件的名称
event.stopPropagation()阻止事件进行冒泡传播,仅在$emit事件中有效
event.preventDefault()阻止默认事件的发生
event.defaultPrevented如果调用了preventDefault事件则返回true

事件传播的方向如下图:

这里写图片描述


1、$emit
该服务贯穿作用域发出一个向上的事件,该事件的生命周期开始于emit被启动的地方,事件一直朝着根作用域传递,传递期间会通知那些注册在作用域上的监听器,在这期间,作用域中的监听器接收到通知,获取事件,但是不会注销事件,事件继续往下传播。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="fatherCtrl">
    <!--fatherCtrl可以得到-->
    <input type="text" ng-model="name" ng-change="nameOnChange()">
    <h1>Father: {{name}}!</h1>
    <div ng-controller="sonCtrl">
        <!--sonCtrl可以得到-->
        <input type="text" ng-model="name" ng-change="nameOnChange()">
        <h1>Son: {{name}}</h1>
        <div ng-controller="innerCtrl">
            <input type="text" ng-model="name" ng-change="nameOnChange()">
            <h1>inner: {{name}}</h1>
        </div>
    </div>
    <div ng-controller="broCtrl">
        <!--broCtrl得不到-->
        <input type="text" ng-model="name" ng-change="nameOnChange()">
        <h1>brother: {{name}}</h1>
    </div>
</div>

<script>
    var app = angular.module('myApp', []);
    app.controller('fatherCtrl', function ($scope) {
        $scope.name = "father";
        $scope.$on('test', function (e, newName) {
            $scope.name = newName;
        });
    });
    app.controller('sonCtrl', function ($scope) {
        $scope.name = "son";
        $scope.$on('test', function (e, newName) {
            $scope.name = newName;
        });
    });
    app.controller('broCtrl', function ($scope) {
        $scope.name = "brother";
        $scope.$on('test', function (e, newName) {
            $scope.name = newName;
        });
    });
    app.controller('innerCtrl', function ($scope) {
        $scope.name = "inner";
        $scope.nameOnChange = function () {
            $scope.$emit('test', $scope.name);
        }
    });
</script>
</body>


</html>



效果如下:

这里写图片描述



2、$broadcast
该服务发布一个向下的事件给作用域中的所有子节点,该事件的生命周期也是从broadcast被启动开始。下面的所有子作用域都会接收到通知。之后,事件向下传播,在这期间,作用域中的监听器接收到通知,获取事件,但是不会注销事件,事件继续往下传播。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="fatherCtrl">
    <!--fatherCtrl得不到-->
    <input type="text" ng-model="name" ng-change="nameOnChange()">
    <h1>Father: {{name}}!</h1>
    <div ng-controller="sonCtrl">
        <input type="text" ng-model="name" ng-change="nameOnChange()">
        <h1>Son: {{name}}</h1>
        <div ng-controller="outCtrl">
            <!--outCtrl可以得到-->
            <input type="text" ng-model="name" ng-change="nameOnChange()">
            <h1>out in son: {{name}}</h1>
            <div ng-controller="innerCtrl">
                <!--innerCtrl可以得到-->
                <input type="text" ng-model="name" ng-change="nameOnChange()">
                <h1>inner in out: {{name}}</h1>
            </div>
        </div>
    </div>
    <div ng-controller="broCtrl">
        <!--broCtrl得不到-->
        <input type="text" ng-model="name" ng-change="nameOnChange()">
        <h1>brother: {{name}}</h1>
    </div>
</div>

<script>
    var app = angular.module('myApp', []);
    app.controller('fatherCtrl', function ($scope) {
        $scope.name = "father";
        $scope.$on('test', function (e, newName) {
            $scope.name = newName;
        });
    });
    app.controller('sonCtrl', function ($scope) {
        $scope.name = "son";
        $scope.nameOnChange = function () {
            $scope.$broadcast('test', $scope.name);
        }
    });
    app.controller('broCtrl', function ($scope) {
        $scope.name = "brother";
        $scope.$on('test', function (e, newName) {
            $scope.name = newName;
        });
    });
    app.controller('innerCtrl', function ($scope) {
        $scope.name = "inner";
        $scope.$on('test', function (e, newName) {
            $scope.name = newName;
        });
    });
    app.controller('outCtrl', function ($scope) {
        $scope.name = "out";
        $scope.$on('test', function (e, newName) {
            $scope.name = newName;
        });
    });
</script>
</body>


</html>



效果如图:

这里写图片描述

3、$on
该服务监听指定类型的事件,获取从emit或者broadcast发布的事件。


注:
1、如果在作用域中没有父子关系存在,可以在控制器中注入$rootScope、使用$broadcast服务向下传播事件(但这个慎用),但是不能通过$emit向上传播事件。

2、在作用域中存在父子关系时,可以也仅可以由子控制器使用$emit服务向上传播事件,同时父作用域中的控制监听器可以注销事件。





参考链接:
1.https://www.jianshu.com/p/afb5dc7ac89a
2.http://blog.csdn.net/licheng11403080324/article/details/52123771
3.http://www.angularjs.cn/A08c
4.https://www.cnblogs.com/CraryPrimitiveMan/p/3679552.html

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Vue,$on、$off、$emit是一些用于组件间通信的方法。可以通过使用$bus实例来传递非父子组件之间的数据。比如,使用$emit方法发送事件,使用$on方法监听事件,使用$off方法移除事件的绑定。 在子组件,可以通过this.$bus.$emit(eventName, payload)来触发一个事件并传递数据。比如子组件1可以使用this.$bus.$emit("hello", param)来触发名为"hello"的事件,并将param作为数据传递。 在组件,可以使用this.$bus.$on(eventName, callback)来监听一个事件。当触发了该事件时,绑定的回调函数将被调用。比如在子组件可以使用this.$on('closeModal', res => {})来监听名为"closeModal"的事件。 同时,也可以使用this.$bus.$off(eventName)来移除绑定的事件。比如在组件销毁前,可以使用this.$off("closeModal")来移除对"closeModal"事件的监听。 通过使用$on、$off、$emit这些方法,可以方便地在Vue组件间进行通信和数据传递。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [vue$bus的用法及$emit、$on、$off的使用](https://blog.csdn.net/leijie0322/article/details/128210817)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [vue$emit跟$on,$off跟用法](https://blog.csdn.net/Billow_lamb/article/details/115007731)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [$emit,$on,$off--vue](https://blog.csdn.net/weixin_57844432/article/details/126599659)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值