Angular 中的全局事件 [英] Global Events in Angular

查看:35
本文介绍了Angular 中的全局事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Angular 中没有与 $scope.emit()$scope.broadcast() 等效的吗?

Is there no equivalent to $scope.emit() or $scope.broadcast() in Angular?

我知道 EventEmitter 的功能,但据我所知,它只会向父 HTML 元素发出一个事件.

I know the EventEmitter functionality, but as far as I understand that will just emit an event to the parent HTML element.

如果我需要在 fx.xml 之间进行通信怎么办?DOM 根中的组件和嵌套多层深的元素之间的兄弟或组件?

What if I need to communicate between fx. siblings or between a component in the root of the DOM and an element nested several levels deep?

推荐答案

没有等效于 $scope.emit()$scope.broadcast() fromAngularJS.组件内部的 EventEmitter 接近,但正如您提到的,它只会向直接父组件发出事件.

There is no equivalent to $scope.emit() or $scope.broadcast() from AngularJS. EventEmitter inside of a component comes close, but as you mentioned, it will only emit an event to the immediate parent component.

在 Angular 中,还有其他替代方案,我将在下面尝试解释.

In Angular, there are other alternatives which I'll try to explain below.

@Input() 绑定允许应用程序模型连接到有向对象图中(根到叶).组件的更改检测器策略的默认行为是将所有更改传播到应用程序模型,以便从任何连接的组件进行所有绑定.

@Input() bindings allows the application model to be connected in a directed object graph (root to leaves). The default behavior of a component's change detector strategy is to propagate all changes to an application model for all bindings from any connected component.

旁白:有两种类型的模型:视图模型和应用程序模型.应用程序模型通过@Input() 绑定连接.视图模型只是一个组件属性(没有用@Input() 修饰),它绑定在组件的模板中.

Aside: There are two types of models: View Models and Application Models. An application model is connected through @Input() bindings. A view model is a just a component property (not decorated with @Input()) which is bound in the component's template.

回答您的问题:

如果我需要在兄弟组件之间进行通信怎么办?

What if I need to communicate between sibling components?

  1. 共享应用模型:兄弟姐妹可以通过共享的应用程序模型进行通信(就像 angular 1 一样).例如,当一个兄弟对模型进行更改时,另一个绑定到同一模型的兄弟会自动更新.

  1. Shared Application Model: Siblings can communicate through a shared application model (just like angular 1). For example, when one sibling makes a change to a model, the other sibling that has bindings to the same model is automatically updated.

组件事件:子组件可以使用@Output() 绑定向父组件发出事件.父组件可以处理事件,并操纵应用程序模型或其自己的视图模型.对应用程序模型的更改会自动传播到直接或间接绑定到同一模型的所有组件.

Component Events: Child components can emit an event to the parent component using @Output() bindings. The parent component can handle the event, and manipulate the application model or it's own view model. Changes to the Application Model are automatically propagated to all components that directly or indirectly bind to the same model.

服务事件:组件可以订阅服务事件.例如,两个兄弟组件可以订阅同一个服务事件,并通过修改各自的模型来响应.详情请见下文.

Service Events: Components can subscribe to service events. For example, two sibling components can subscribe to the same service event and respond by modifying their respective models. More on this below.

如何在根组件和嵌套多层的组件之间进行通信?

How can I communicate between a Root component and a component nested several levels deep?

  1. 共享应用程序模型:应用程序模型可以通过@Input() 绑定从根组件向下传递到深层嵌套的子组件.任何组件对模型的更改都会自动传播到共享同一模型的所有组件.
  2. 服务事件:您还可以将 EventEmitter 移动到共享服务,这允许任何组件注入服务并订阅事件.这样,一个 Root 组件可以调用一个服务方法(通常是改变模型),该方法又会发出一个事件.再往下几层,一个孙子组件也注入了服务并订阅了相同的事件,可以处理它.任何更改共享应用程序模型的事件处理程序都会自动传播到所有依赖它的组件.这可能与 Angular 1 中的 $scope.broadcast() 最接近.下一节将更详细地描述这个想法.
  1. Shared Application Model: The application model can be passed from the Root component down to deeply nested sub-components through @Input() bindings. Changes to a model from any component will automatically propagate to all components that share the same model.
  2. Service Events: You can also move the EventEmitter to a shared service, which allows any component to inject the service and subscribe to the event. That way, a Root component can call a service method (typically mutating the model), which in turn emits an event. Several layers down, a grand-child component which has also injected the service and subscribed to the same event, can handle it. Any event handler that changes a shared Application Model, will automatically propagate to all components that depend on it. This is probably the closest equivalent to $scope.broadcast() from Angular 1. The next section describes this idea in more detail.

使用服务事件传播更改的可观察服务示例

这是一个使用服务事件来传播更改的可观察服务的示例.添加 TodoItem 后,该服务会发出一个事件通知其组件订阅者.

Here is an example of an observable service that uses service events to propagate changes. When a TodoItem is added, the service emits an event notifying its component subscribers.

export class TodoItem {
    constructor(public name: string, public done: boolean) {
    }
}
export class TodoService {
    public itemAdded$: EventEmitter<TodoItem>;
    private todoList: TodoItem[] = [];

    constructor() {
        this.itemAdded$ = new EventEmitter();
    }

    public list(): TodoItem[] {
        return this.todoList;
    }

    public add(item: TodoItem): void {
        this.todoList.push(item);
        this.itemAdded$.emit(item);
    }
}

以下是根组件订阅事件的方式:

Here is how a root component would subscribe to the event:

export class RootComponent {
    private addedItem: TodoItem;
    constructor(todoService: TodoService) {
        todoService.itemAdded$.subscribe(item => this.onItemAdded(item));
    }

    private onItemAdded(item: TodoItem): void {
        // do something with added item
        this.addedItem = item;
    }
}

嵌套多层的子组件会以同样的方式订阅事件:

A child component nested several levels deep would subscribe to the event in the same way:

export class GrandChildComponent {
    private addedItem: TodoItem;
    constructor(todoService: TodoService) {
        todoService.itemAdded$.subscribe(item => this.onItemAdded(item));
    }

    private onItemAdded(item: TodoItem): void {
        // do something with added item
        this.addedItem = item;
    }
}

这里是调用服务触发事件的组件(它可以驻留在组件树中的任何位置):

Here is the component that calls the service to trigger the event (it can reside anywhere in the component tree):

@Component({
    selector: 'todo-list',
    template: `
         <ul>
            <li *ngFor="#item of model"> {{ item.name }}
            </li>
         </ul>
        <br />
        Add Item <input type="text" #txt /> <button (click)="add(txt.value); txt.value='';">Add</button>
    `
})
export class TriggeringComponent{
    private model: TodoItem[];

    constructor(private todoService: TodoService) {
        this.model = todoService.list();
    }

    add(value: string) {
        this.todoService.add(new TodoItem(value, false));
    }
}

参考:Angular 中的变更检测

这篇关于Angular 中的全局事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆