angular 1.7.5_了解Angular 1.5生命周期挂钩

angular 1.7.5

The release of Angular 1.5 has introduced some powerful features that have made Angular 1.x fun and easy to use. One of this features is the lifecycle hooks.

Angular 1.5的发行版引入了一些强大的功能,这些功能使Angular 1.x变得有趣且易于使用。 此功能之一是生命周期挂钩。

生命周期挂钩 ( Lifecycle Hooks )

Lifecycle hooks were introduced to Angular in Angular 2 alpha. They were more or less inspired by the custom elements lifecycle callbacks.

生命周期挂钩在Angular 2 alpha中引入了Angular。 他们或多或少地受到了自定义元素生命周期回调的启发。

Angular 2生命周期挂钩 (Angular 2 Lifecycle Hooks)

This means that they are not actually the same so to speak. Angular 2 components come with lifecycle hooks like ngOnInit(), ngOnDestroy(), ngOnChanges(), and many more. In a nutshell, these lifecycle hooks do the following:

这意味着可以说它们实际上并不相同。 Angular 2组件带有生命周期挂钩,例如ngOnInit()ngOnDestroy()ngOnChanges()等等。 简而言之,这些生命周期挂钩将执行以下操作:

  • ngOnInit(): Initialize the component and the grab the necessary objects/variables we might need

    ngOnInit() :初始化组件并获取我们可能需要的必要对象/变量
  • ngOnDestroy(): Cleanup the component just before Angular destroys it. Useful for unsubscribing from observables to avoid memory leaks

    ngOnDestroy() :在Angular销毁组件之前对其进行清理。 用于取消订阅可观察对象以避免内存泄漏
  • ngOnChanges(): Do something when Angular sets a data-bound property

    ngOnChanges() :Angular设置数据绑定属性时执行某些操作

For detailed information visit the offfial docs.

有关详细信息,请访问官方文档

Angular 1生命周期挂钩 (Angular 1 Lifecycle Hooks)

Angular 1.x is evolving in a way to keep the gap and migration to Angular 2 as small as possible. With the introduction of .component() method, some lifecycle callbacks have been backported to Angular 1.

Angular 1.x正在不断发展,以保持差距和向Angular 2的迁移尽可能小。 随着.component()方法的引入,一些生命周期回调已被反向移植到Angular 1。

Some of these hooks Include:

这些钩子包括:

  • $onInit()

    $onInit()
  • $onChanges()

    $onChanges()
  • $onDestroy()

    $onDestroy()
  • $postLink()

    $postLink()

Let's look at them one by one. Please note that Angular lifecycle-hooks were introduced in version 1.5.3.

让我们一一看一下。 请注意,Angular生命周期挂钩是在1.5.3版中引入的。

Note: module as used in this tutorial refers to the angular module as shown below.

注意:本教程中使用的module是指如下所示的角度模块。

var module = angular.module('lifeCycleModule', []);

$ onInit() ( $onInit() )

This lifecycle is executed when all controllers on the element have been constructed and after their bindings are initialized.

当元素上的所有控制器都已构造好并且绑定初始化后,将执行此生命周期。

This hook is meant to be used for any kind of initialization work for the controller. Imagine you have a view which when visited should be populated with a list of users on load.

该钩子可用于控制器的任何类型的初始化工作。 想象一下,您有一个视图,该视图在访问时应填充有正在加载的用户列表。

Normally you would write a function that would be called when the controller constructed, for example.

例如,通常您会编写一个在构造控制器时会调用的函数。

...
function MyController() {
  /**
   * Initializing using custom method init
   */

  this.init = function () {
    this.users = ['user1', 'user2', 'user3'];
  };

  /**
   * When the controller is constructed, this method will be called
   */

  this.init();
}
...

Another approach is to directly initialize the list of users to a variable:

另一种方法是直接将用户列表初始化为变量:

...
/**
 * Initialize users directly in the controller
 */
function MyController() {
  this.users = ['user1', 'user2', 'user3'];
}
...

All the above examples work, but now imagine if you have to make HTTP request to the server to get our users, this means we'd have to mock this requests every time we construct this component or controller.

以上所有示例均有效,但现在想象一下,如果您必须向服务器发出HTTP请求以获取我们的用户,这意味着我们每次构造此组件或控制器时都必须模拟此请求。

Wouldn't it be nice if we had some hook that would handle this for us? Now we have the $onInit lifecycle hook. Thanks to $onInit, we can now write the above code as below.

如果我们有一些钩子可以为我们解决这个问题,那不是很好吗? 现在我们有了$onInit生命周期挂钩。 多亏了$onInit ,我们现在可以如下编写上面的代码。

...
function MyController() {

  /**
   * [$onInit: Initializes users with an array of objects]
   *
   * We can also make http request in this hook if needed
   * especially when you are getting data from a server
   */
  this.$onInit = function () {
    this.users = [{
        "id": 1,
        "name": "Leanne Graham",
        "username": "Bret",
        "email": "Sincere@april.biz",
        "phone": "1-770-736-8031 x56442",
        "website": "hildegard.org",
        "company": {
          "name": "Romaguera-Crona",
          "catchPhrase": "Multi-layered client-server neural-net"
        }
      },
      ...

    ];
  };

}
....

we can access the users in our template as follows:

我们可以按以下方式访问模板中的用户:

....<div class="container">
  <table class="bordered striped highlight">
    <thead>
      <tr>
        <th data-field="name">Name</th>
        <th data-field="username">username</th>
        <th data-field="email">E-mail</th>
        <th data-field="city">city</th>
        <th data-field="Phone">Phone Number</th>
        <th data-field="website">website</th>
        <th data-field="company">company</th>
      </tr>
    </thead>
    <tbody>
      <tr ng-repeat="user in users">
        <td>{{ user.name }}</td>
        <td>{{ user.username }}</td>
        <td>{{ user.email }}</td>
        <td>{{ user.address.city }}</td>
        <td>{{ user.phone }}</td>
        <td>{{ user.website }}</td>
        <td>{{ user.company.name }}</td>
      </tr>
    </tbody>
  </table>
</div>
....

Any data that we need before we begin processing any logic should be handled in this hook. This gives us better control of our component data flow.

在开始处理任何逻辑之前需要的所有数据都应在此挂钩中处理。 这使我们可以更好地控制组件数据流。

In the above example, when the component is constructed, the $onInit lifecycle hook will run the function attached to it and populate the users variable with an array of users. Here is a codepen for this example.

在上面的示例中,在构造组件时, $onInit生命周期挂钩将运行附加到该组件的函数,并使用用户数组填充users变量。 这是此示例的一个代码笔。

组件间通信 (Inter-component communication)

Now imagine you need to access the parent component controllers, how would you go about this. With $onInit we can access controllers of the parent components through the require property.

现在假设您需要访问父组件控制器,您将如何处理。 使用$onInit我们可以通过require属性访问父组件的控制器。

This means we don't need link() functions to access other directives controllers - If you are using .directive() method helper to build components.

这意味着我们不需要link()函数来访问其他指令控制器-如果您使用.directive()方法助手来构建组件。

Let us use a scenario where we are building a tabs and tab component. The tab component being the child component needs to access the TabsController to register itself, we can simply use the require property and call it directly via the component instance. Let's see an example.

让我们使用一种构建tabstab组件的方案。 作为子组件的tab组件需要访问TabsController进行注册,我们可以简单地使用require属性并通过组件实例直接调用它。 让我们来看一个例子。

...
/**
 * [TabController]
 */
function TabController ( ) {
  /**
   * [addTab description]
   * @param {component} tab [The component to be registered]
   */
  this . addTab = function ( tab ) {
    // some code to register component
  } ;
}

/**
 * [template: Tab component template]
 * @type {String}
 * [controller: Component controller]
 * @type { function}
 */
module . component ( 'myTabs' , {
  template : '<div> <!-- some code for tabs--></div> ' ,
  controller : TabController
} ) ;
...

In the code snippet above we have built a Tab component, but a tab without panel is not what we want. We need to add a TabPanel component which will be a child of myTab component.

在上面的代码片段中,我们构建了一个Tab组件,但是没有面板的Tab并不是我们想要的。 我们需要添加一个TabPanel组件,该组件将是myTab组件的myTab

...
/**
 * TabPanelController
 */
function TabPanelController ( ) {
  /**
   * [$onInit registers panel to parent component]
   */
  this . $onInit = function ( ) {
    this . parent . addTab ( this ) ;
  } ;

}

/**
 * [template panel template]
 * @type {String}
 *
 * [require gives access to the parent tab component]
 * @type {Object}
 */
module . component ( 'TabPanel' , {
  require : {
    'parent' : '^myTabs'
  } ,
  template : '<div> <!-- template for tab--></div>' ,
  controller : TabPanelController
} ) ;
...

Simple and clean.

简单干净。

$ onChanges() ( $onChanges() )

When building components at one point you will have data coming into your component from an external source e.g parent component. With ``$onChanges` we can react to this changes and update the child component data effectively.

在某一时刻构建组件时,您将有来自外部源(例如父组件)的数据进入您的组件。 使用``$ onChanges`,我们可以对这些更改做出React并有效地更新子组件数据。

Before we go ahead into examples it is important for us to understand, how, why and when this hook is called. $onChanges hook is called in two scenarios, one being during component initialization, it passes down the initial changes that can be used right away through isFirstChange method.

在继续进行示例之前,对于我们来说,重要的是要了解,如何,为什么以及何时调用此挂钩。 $onChanges挂钩在两种情况下被调用,一种是在组件初始化期间,它传递可通过isFirstChange方法立即使用的初始更改。

function Mycontroller ( ) {
  /**
   * Get the inital changes when the component is initilaized
   * Assuning we passed name from the parent
   * <our-component name="ValueOfName"></our-component>
   */

  this . $onChanges = function ( changes ) {

    if ( changes . user . isFirstChange ( ) ) {

      this . name = changes . user . currentValue ;
    }

  } ;
}

The other scenario is when changes occur in one way bindings < and evaluated DOM attributes @. It propagates this changes down to the child component which we would re-assign to our local component.

另一种情况是,更改以一种方式发生,绑定<和评估的DOM属性@ 。 它将更改传播到子组件,然后将其重新分配给本地组件。

Let's look at an example. We have this two dudes who like to be greeted differently, Thomas likes Howdy and John the old Hello.

让我们来看一个例子。 我们有两个喜欢打招呼的家伙,托马斯喜欢霍迪,而约翰则喜欢老哈罗。

...
/**
 * [MyController: Greets user with an name]
 */
function MyController ( ) {
  this . greeting = 'Hello ' + this . name ;
}

module . component ( 'onChanges' , {
  template : '<h1>{{$ctrl.greeting}}</h1>' ,
  controller : MyController
} ) ;
...

If we run this component with <on-changes name="'John'"> we will get Hello John output. What do you this will happen if we change the name attribute value to Thomas?

如果我们使用<on-changes name="'John'">运行此组件,我们将获得Hello John输出。 如果将name属性值更改为Thomas您将发生什么?

< on-changes name = " ' Thomas ' " > </ on-changes >

We still get Hello Thomasas output. This will make Thomas angry and we don't want that to happen? To remedy this situation, we need to detect changes on the name attribute and respond with the appropriate greeting. Let's do that.

我们仍然得到Hello Thomas作为输出。 这会让托马斯生气,我们不希望那样发生吗? 为了解决这种情况,我们需要检测对name属性的更改并以适当的问候进行响应。 来做吧。

...
function MyController ( ) {
  this . $onChanges = function ( obj ) {
    var prefix ;
    /**
     * [if: checks when the name has changed and greet the persons appropriately]
     */

    if ( obj . name && this . name ) {
      ( obj . name . currentValue . toLowerCase ( ) === 'thomas' ) ? prefix = 'Howdy ' : prefix = 'Hello ' ;
      this . greeting = prefix + this . name ;
    }

    /**
     * If: checks if the name is not defined set greeting to empty string
     */

    if ( ! this . name ) {
      this . greeting = '' ;
    }
  } ;
}

module . component ( 'onChanges' , {
  template : '<h1>{{$ctrl.greeting}}</h1>' ,
  controller : MyController
} ) ;
...

The $onChanges() passes down a hash with property of the bound attribute in this case name and a function isFirstChange(). The property contains two other properties currentValue which has the current value of the bound attribute and previousValue the value we have changed from. The function isFirstChange can be used to get the initial value when the component is initialized. Using these properties we can track the changes and reflect them on the view.

$onChanges()在此情况下传递具有绑定属性属性的哈希$onChanges()在这种情况下为name和函数isFirstChange() 。 该属性包含其他两个属性currentValue ,该属性具有bound属性的当前值,而value则是我们从中更改的previousValue值。 组件初始化时,函数isFirstChange可用于获取初始值。 使用这些属性,我们可以跟踪更改并将其反映在视图上。

In the example above we have used obj.name.currentValue to access the current name from the attribute. We then get the current name from the attribute, check if its Thomas and if it is then we use Howdy to greet him. Otherwise, we will use Hello.

在上面的示例中,我们使用obj.name.currentValue从属性访问当前名称。 然后,我们从属性中获取当前名称,检查其名称是否为Thomas ,如果是,则使用Howdy问候他。 否则,我们将使用Hello

Here is the CodePen:

这是CodePen:

The big picture of one-way data flow is to replace default two-way data-binding syntax =. Ideally, we can delegate functions from the parent component through & bindings, to which the child component will use $event to pass data back to the parent component. The combination of $onChanges + < + & brings to live the concept of uni-directional data flow.

单向数据流的概况是替换默认的两向数据绑定语法= 。 理想情况下,我们可以通过&绑定从父组件中委派功能,子组件将使用$event将数据传递回父组件。 $onChanges + < + &的组合带来了单向数据流的概念。

Let's look at an example of how we can achieve this.

让我们看一个如何实现此目标的示例。

module.component('parentComponent', {
  controller: function () {
    /**
     * Initial name
     */

    this.name = 'Marcus Johns';

    /**
     * This method will be called when changes happen in the child component.
     */

    this.updateName = function (event) {
      this.name = event.name;
    };
  },

  template: `

    <p>The parent object: {{ $ctrl.name }} </p>
    <input type="text" ng-model="$ctrl.name">
    <child-component name="$ctrl.name" on-update="$ctrl.updateName($event)"><child-component>`
});


module.component('childComponent', {
  bindings: {
    name: '<',
    onUpdate: '&'
  },
  controller: function () {

    var self = this;

    self.$onChanges = function (changes) {
      self.name = angular.copy(changes.name.currentValue);
    };

    /**
     * When the button is clicked we can update the parent component
     */

    self.updateData = function () {
      self.onUpdate({
        $event: {
          name: self.name
        }
      });
    };
  },
  template: `
  <p> child component: {{ $ctrl.name }}</p>
  <input type="text" ng-model="$ctrl.name">
  <button class="btn" ng-click="$ctrl.updateData()"> Update </button>`
});

In the above example we have two components the parent and child component. Through one way data binding the parent component passed down the value of name to the child component.

在上面的示例中,我们有两个组件,父组件和子组件。 通过一种数据绑定方式,父组件将name的值传递给子组件。

The changes from the parent component will trigger the $onChanges hook wich will clone the value of the name that we get from the changes and re-assign it to self.name in our child component.

父组件的更改将触发$onChanges挂钩,它将克隆我们从更改中获取的名称的值,并将其重新分配给子组件中的self.name

The reason why we are cloning the value is to treat the value from the parent component as immutable to avoid any nasty surprises. This enables us to manipulate the data passed down to us without affecting the parent.

我们克隆值的原因是将父组件中的值视为不可变的,以避免任何令人讨厌的意外。 这使我们能够操纵传递给我们的数据而不会影响父级。

So what happens when data changes in our child components?

那么,当子组件中的数据发生变化时会发生什么呢?

In our bindings we specified one-way data binding meaning we only get data coming in from the parent but nothing is getting out.

在我们的绑定中,我们指定了单向数据绑定,这意味着我们仅从父级获取数据,但没有任何输出。

To notify the parent component of changes from the child component, we have delegated a function onUpdate. This function enables us to access this.updateName function in the parent component. When the update button is clicked, self.updateData will in turn call the parent this.updateName with the new value of name. This is achieved through the delegated function self.onUpdate.

为了将子组件的更改通知给父组件,我们委托了一个函数onUpdate 。 这个函数使我们能够访问父组件中的this.updateName函数。 单击更新按钮时, self.updateData会依次使用新name调用父this.updateName 。 这是通过委托函数self.onUpdate

Here the CodePen. http://codepen.io/thomasnyambati/pen/NABarq

这里是CodePen。 http://codepen.io/thomasnyambati/pen/NABarq

$ onDestroy() ( $onDestroy() )

This hook is called when its containing scope is destroyed. We can use this hook to release external resources, watches and event handlers. This is basically the same as $scope.on($destroy, fn) when used in controllers.

当其包含的作用域被破坏时,将调用此钩子。 我们可以使用此钩子释放外部资源,监视和事件处理程序。 在控制器中使用时$scope.on($destroy, fn)这基本上与$scope.on($destroy, fn)相同。

...
  $scope.on('$destroy', function() {
    // do some cleaning in here.
  });
...

In a scenario where you have attached non-native angular event listeners or logic, we can use this hook to clean it up when the component is destroyed.

在附加了非本机角度事件侦听器或逻辑的情况下,当组件被销毁时,我们可以使用此钩子对其进行清理。

...
function MyController($element) {
  /**
   * eventHandler: custom event handler to be attached to our element]
   */
  var eventHandler = function () {
    /**
     * Do something cool in here
     */
  };

  /**
   * [$onInit: Attach our eventHandler when the element is clicked]
   */

  this.$onPostLink = function () {

    // When the component DOM has been compiled attach you eventHandler.

  };

  /**
   * [$onDestroy: Destroy the eventHandler once the component is destroyed]
   */
  this.$onDestroy = function () {

    // Destroy all custom events or bindings when the component scope is destroyed.

  };

}
...

When our component is constructed, we attach a click event to the component element that does something to it when clicked, it can be wherever we want let's say show alert box saying I am clicked.

构造组件时,我们将click事件附加到component元素上,该事件会在单击时对其执行某些操作,它可以在我们想要的任何地方,比如说显示警告框说I am clicked

In the duration when this component is active we would be happy to have this event, but when this component is inactive (meaning we have destroyed it), we don' t need this event anymore it has to go.

在此组件处于活动状态的过程中,我们很高兴收到此事件,但是当此组件处于不活动状态(意味着我们已销毁它)时,我们就不再需要此事件。

Since this our custom event and it's not native to Angular, it will not be detached from our app along with the component, but it will be left snooping around for an element which does not exist.

由于这是我们的自定义事件,并且它不是Angular的本地事件,因此它不会与组件一起从我们的应用程序中分离出来,但是会被窥探到不存在的元素。

We need to tell Angular through the $onDestroy hook when you destroy this component detach this event too.

当您销毁该组件时,我们也需要通过$onDestroy钩子告诉Angular,也要分离此事件。

This hook is called after the controller's element and its children have been linked. When the component elements have been compiled and ready to go, this hook will be fired.

在链接控制器的元素及其子元素之后,将调用此挂钩。 组件元素已编译并准备就绪后,将触发此挂钩。

...
function MyController($element) {
  /**
   * When the element and its child nodes have been compiled
   */

  this.$postLink = function () {
    /**
     * Do something awesome in here
     */

  };

}
...

This hook can help us to implement some functionalities that depend on the component elements to be fully compiled.

这个钩子可以帮助我们实现某些功能,这些功能取决于要完全编译的组件元素。

It is important to note that this is not a complete replacement for DOM manipulation, this functionality should be handled by decorator directives.

重要的是要注意,这不能完全替代DOM操作,此功能应由装饰器指令处理。

结论 ( Conclusion )

Lifecycle hooks provide us with an easy way of invoking operation based on the lifecycle of our components. Using this hooks lets us provide our users with relevant information or action at the appropriate time.

生命周期挂钩为我们提供了一种基于组件生命周期的简便操作调用方式。 使用此挂钩可以让我们在适当的时候为用户提供相关信息或操作。

For more details refer to understanding components docs. It's important that you practice what we have discussed above in order to have a deeper understanding of how and where to use these hooks.

有关更多详细信息,请参阅了解组件文档 。 重要的是,您必须实践我们上面讨论的内容,以便对如何以及在何处使用这些挂钩有更深入的了解。

Go out there and be creative.

到那里去并发挥创造力。

翻译自: https://scotch.io/tutorials/understanding-angular-1-5-lifecycle-hooks

angular 1.7.5

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值