在 Angular 1.x 中通信组件或指令的有效方式

Posted

技术标签:

【中文标题】在 Angular 1.x 中通信组件或指令的有效方式【英文标题】:Efficient way to communicate components or directives in Angular 1.x 【发布时间】:2016-06-02 06:23:50 【问题描述】:

根据下图:

我想改进组件通信方式....我认为这种方式效率不高。

当点击 tabsetComponent 发出事件时,父控制器会捕捉到这个事件,改变 rootScope 变量。使用tableComponent中的$watch rootScope变量触发http获取数据函数...

谁能有更好更有效的方式来交流兄弟组件?

【问题讨论】:

【参考方案1】:

公认的组件间通信的AngularJS方法是使用组件属性进行通信。

<div ng-controller="rootCtrl as vm">

    <tab-set-component tsc-click="vm.fn($event, data)">
    </tab-set-component>

    <table-component="vm.tableData">
    </table-component>

</div>

有关定义组件属性的更多信息,请参阅AngularJS Comprehensive Directive API -- isolate scope

最佳做法

仅将.$broadcast().$emit().$on() 用于原子事件

在整个应用程序中全局相关的事件(例如用户身份验证或应用程序关闭)。如果您想要特定于模块、服务或小部件的事件,您应该考虑服务、指令控制器或 3rd 方库

$scope.$watch() 应该取代对事件的需求 直接注入服务和调用方法对于直接通信也很有用 指令可以通过指令控制器直接相互通信

-- AngularJS Wiki Best Practices


控制器示例

在您的 html 中,您使用来自根控制器的 vm.fn 对吗?所以你的建议是应该调用定义根控制器的click方法,click方法会触发rootScope上定义的http请求函数,然后获取表格组件数据,然后绑定表格组件属性上的数据。

例如:

angular.module("myApp", []);

angular.module("myApp").controller("rootCtrl", function($http) 
    var vm = this;

    vm.tableData =  /* initial data */ ;

    //click handler
    vm.fn = function(event, url) 
        $http.get(url).then (function onFulfilled(response) 
            vm.tableData = response.data;
        ).catch (function onRejected(response) 
            console.log(response.status);
        );
    ;
);

上面的例子避免了混乱的$rootScope。所有的业务逻辑和数据都包含在控制器中。

控制器为table-component设置初始数据,从tab-set-component接收点击事件,发出HTTP请求,处理错误,并将数据更新到table-component


更新 -- 使用表达式绑定

另一种方法是使用表达式绑定来传递事件:

<header-component view="root.view" on-view-change="root.view = $event.view">
</header-component>

<main-component view="root.view"></main-component>

欲了解更多信息,请参阅SO: How to pass data between sibling components in angular, not using $scope

在 1.5.3 版本中,AngularJS 将 $onChanges 生命周期挂钩添加到 $compile 服务。

app.component("mainComponent",  
      template: "<p>$ctrl.count",
      bindings: view: '<',
      controller: function() 
        this.count = 0;
        this.$onChanges = function(changesObj) 
            if (changesObj.view) 
                this.count++;
                console.log(changesObj.view.currentValue);
                console.log(changesObj.view.previousValue);
                console.log(changes)bj.view.isFirstChanged());
            ;
        ;    
      
);

欲了解更多信息,请参阅AngularJS Comprehensive Directive API Reference -- Life-cycle hooks

另见SO: AngularJs 1.5 - Component does not support Watchers, what is the work around?

【讨论】:

在您的 html 中,您使用来自根控制器的 vm.fn 对吗?所以你的建议是它应该调用根控制器上定义的click方法,click方法将触发rootScope上定义的http请求函数,然后获取表组件数据,然后绑定表组件属性上的数据。你认为在根控制器中定义 http fetch 函数效率更高吗?而且通过这些方式,我们不需要使用任何事件方法,对吗? 查看添加的控制器示例 感谢您的详细解释:) 另一个问题,如果根范围内有很多组件,我们将在根控制器中定义很多功能,是正确的方法吗?根控制器会太重而无法高效执行? 上面的控制器示例没有使用$rootScope。它使用$rootScope 的子作用域。您可以通过将'scope-id'=+$id 放入其模板中来检查。 $rootScope 的 ID 为 1。子作用域的数字从 1 递增。 对不起,我打错字了...其实我想说的是,如果我在根控制器中定义了很多根控制器中的组件需要的功能,那么根控制器会不会太重?

以上是关于在 Angular 1.x 中通信组件或指令的有效方式的主要内容,如果未能解决你的问题,请参考以下文章

Angular组件通信和指令的使用

Angular (v2) 扩展系列组件通信(无父或外部服务)

Angular 2~6:与“组件”通信的最有效方式是啥?

在 Angular 结构指令中使用动态组件会产生额外的 HTML 标记。如何删除或更换它?

在 Angular2 的指令或组件中使 @HostBinding 和 @HostListener 有条件

如何使用多个选择器定义 Angular 2 组件或指令