diff --git a/docs/core-concepts/events.md b/docs/core-concepts/events.md index 660bebb56..dea8c623f 100644 --- a/docs/core-concepts/events.md +++ b/docs/core-concepts/events.md @@ -1,6 +1,6 @@ --- -title: Events -description: How to handle events in NativeScript. +title: Events 事件 +description: How to handle events in NativeScript. 如何在NativeScript中处理事件。 position: 90 slug: events environment: nativescript @@ -9,35 +9,77 @@ previous_url: /events # Events +# 事件 + Contents of this article: +目录: + * [Overview](#overview) + + [概述](#overview) + * [Adding an event handler](#adding-an-event-handler) + + [增加事件处理器](#adding-an-event-handler) + * [Removing an event listener](#removing-an-event-listener) + + [移除事件处理器](#removing-an-event-listener) + * [PropertyChange event](#propertychange-event) + + [PropertyChange事件](#propertychange-event) + * [Creating a custom event](#creating-a-custom-event) + + [创建自定义事件](#creating-a-custom-event) + * [Avoiding memory leaks](#avoiding-memory-leaks) + + [避免内存泄漏](#avoiding-memory-leaks) + * [Working with weak events](#working-with-weak-events) + [使用弱事件](#working-with-weak-events) + ## Overview +## 概述 + An event is a message sent from an event emitter to signify the occurrence of a specific action. This action can be generated by a user action (such as a tap) or by program logic (for instance, to indicate that downloading an image from a server has completed). The object that raises the event is called an **event sender** (simply **sender**) or **event raiser**. The object that consumes the event is called an **event listener** (simply **listener**) or **event handler**. +事件是由事件发生器发出的用于表示一种特定操作的消息。这种操作可能由用户操作(比如一次触摸)或程序逻辑(比如从服务器下载的图片已经下载完毕)产生。产生事件的对象称为**事件发送器(event sender)**(简称为**发送器(sender)**)或是**事件发生器(event raiser)**。消费(consume)该事件的对象称为**事件监听器(event listener)**(简称为**监听器(listener)**)或是**事件处理器(event handler)**。 + The NativeScript framework provides a class `Observable` that powers the process of working with events. Find more information about it in the [API Reference](http://docs.nativescript.org/api-reference/classes/_data_observable_.observable.html). Because it is one of the base classes within the NativeScript framework, almost every NativeScript object (component) has an option for dealing with events. +NativeScript框架提供了一个驱动事件工作流程的`Observable`类,你可以在 [API索引](http://docs.nativescript.org/api-reference/classes/_data_observable_.observable.html)中查看更多信息。由于它是NativeScript框架中最基础的类之一,因此几乎每个NativeScript对象(组件)都拥有处理事件的选择。 + ## Adding an Event Handler +## 增加事件处理器 + To add an **event handler** means setting a function (method) that executes when the event is raised. +添加**事件处理器**意味着设置一个函数(或方法),使其在特定事件发生时执行。 + __Example 1__ shows how to set a function that prints a "Hello World!" message in the console when a button is tapped. You can choose between the shorthand syntax and the full syntax or you can declare the event handler in XML. +__例一__ 本例展示了如何编写一个函数,实现在点击按钮时向控制台输出"Hello, World!"消息。可以使用简写语法(shorthand syntax)或者完整语法(full syntax),也可以在XML中声明事件处理器。 + The example below shows how to add an event listener by using the short and full syntax. There is a third optional parameter that represents the `this` argument. -###Example 1 (JavaScript): Adding an event handler or an event listener using the short and full syntax. +下面这个例子展示了如何使用简写语法和完整语法来增加事件监听器。第三个参数是用于指定`this`的可选参数。 + +### Example 1 (JavaScript): Adding an event handler or an event listener using the short and full syntax. + +### 例1(JavaScript):使用简写语法和完整语法来增加事件处理器(或事件监听器)。 + ``` JavaScript //Adding a listener with the short syntax +//使用简写语法来增加事件监听器 var buttonModule = require("ui/button"); var testButton = new buttonModule.Button(); testButton.text = "Test"; @@ -47,6 +89,7 @@ testButton.on(buttonModule.Button.tapEvent, function (eventData) { },this); //Adding a lister with the full syntax +//使用完整语法来增加事件监听器 var testButton2 = new buttonModule.Button(); testButton2.text = "Test"; @@ -56,18 +99,24 @@ var onTap = function (eventData) { testButton2.addEventListener(buttonModule.Button.tapEvent, onTap, this); ``` -###Example 1 (TypeScript): Adding an event handler or an event listener using the short and full syntax. + +### Example 1 (TypeScript): Adding an event handler or an event listener using the short and full syntax. + +### 例1(TypeScript):使用简写语法和完整语法来增加事件处理器(或事件监听器)。 + ``` TypeScript //Adding a listener with the short syntax +//使用简写语法来增加事件监听器 import buttonModule = require("ui/button"); var testButton = new buttonModule.Button(); testButton.text = "Test"; testButton.on(buttonModule.Button.tapEvent, function (eventData) { console.log("Hello World!"); - },this); +},this); //Adding a lister with the full syntax +//使用完整语法来增加事件监听器 var testButton2 = new buttonModule.Button(); testButton2.text = "Test"; @@ -80,7 +129,12 @@ testButton2.addEventListener(buttonModule.Button.tapEvent, onTap, this); Another option to set an event handler is to use an XML declaration. -###Example 1 (XML): Adding an event handler or an event listener using an XML declaration. +也可以使用XML声明的方式来设置事件处理器。 + +### Example 1 (XML): Adding an event handler or an event listener using an XML declaration. + +### 例1 (XML):使用XML声明的方式来增加事件处理器或事件监听器。 + ``` XML @@ -88,9 +142,15 @@ Another option to set an event handler is to use an XML declaration. ``` -You need a code-behind file (see __Example 2__) to write the function body (the code-behind file has the same file name, but a different extension: .js or .ts depending on the language you are using). -###Example 2: Hooking to a button tap event +You need a code-behind file (see __Example 2__) to write the function body (the code-behind file has the same file name, but a different extension: .js or .ts depending on the language you are using). + +这里需要一个代码后置(code-behind)文件(参见 __例2__)来写出函数主体(该文件应当有同样的文件名,后缀名—.js或.ts—取决于于你所使用的语言)。 + +### Example 2: Hooking to a button tap event + +### 例2:挂接(Hook)到按下按钮的事件上 + ``` JavaScript function onTap(eventData) { console.log("Hello World!"); @@ -105,35 +165,58 @@ export function onTap(eventData) { ## Removing an Event Listener +## 移除事件监听器 + Usually you don't need to remove the event listener. You might need to do it when you want to receive the event just once or to free up resources. In such cases, you can apply the methods in __Example 3__. +一般来讲不需要移除事件监听器。如果你希望只监听该事件一次,或者是想要释放占用的资源,你可能需要移除事件监听器。在这些情况下,你可以应用 __例3__ 中提供的方法。 + > There is no syntax to remove an event listener through an XML declaration. +> 不存在通过XML声明来移除事件监听器的语法。 + ### Removing an Event Listener Using the Shorthand or Full Syntax +### 使用简写语法或完整语法来移除事件监听器 + __Example 3__ uses the shorthand and full syntax to remove all listeners for the tap event of the testButton instance. If more than one object are listening for events, you can set a second parameter with the name of the callback function. This way only the referenced event listener is removed. When multiple event listeners with different `this` arguments are available, a third optional parameter is used. -###Example 3: Removing a button tap event listener +__例三__ 使用简写语法和完整语法来移除所有监听testButton实例的触碰(tap)事件的事件监听器。如果有多个对象正在监听事件,可以将第二个参数设定为特定回调函数的名称(name)。使用这种方法,只有所引用的特定事件监听器会被移除。如果需要设置具有不同`this`参数的多个事件监听器,可以使用可选的第三个参数。 + +### Example 3: Removing a button tap event listener + +### 例3:移除监听触碰按钮事件的事件监听器 ``` JavaScript //Removing a listener with short syntax +//使用简写语法移除监听器 testButton.off(buttonModule.Button.tapEvent); //Removing a listener with short syntax +//使用简写语法移除监听器 testButton2.removeEventListener(buttonModule.Button.tapEvent); ``` ``` TypeScript //Removing a listener with short syntax +//使用简写语法移除监听器 testButton.off(buttonModule.Button.tapEvent); //Removing a listener with short syntax +//使用简写语法移除监听器 testButton2.removeEventListener(buttonModule.Button.tapEvent); ``` + ## PropertyChange Event +## PropertyChange事件 + The `Observable` class provides a built-in event called `propertyChange` that is called when a property is changed. __Example 4__ shows how to subscribe to this event. -###Example 4: Handle the propertyChange event +`Observable`类提供一个名为`propertyChange`的内置事件,该事件在属性变化时被调用。__例四__ 展示了如何注册这个事件。 + +### Example 4: Handle the propertyChange event + +### 例4:处理propertyChange事件 ``` JavaScript var observableModule = require("data/observable"); @@ -151,9 +234,14 @@ observableObject.on(observableModule.Observable.propertyChangeEvent, function(pr console.log(propertyChangeData.propertyName + " has been changed and the new value is: " + propertyChangeData.value); }); ``` + It is important to note that the `propertyChange` event is critical for the entire [data binding]({% slug binding %}) system. To take advantage of the data binding mechanism, all you have to do is make your business object **inherit** the `Observable` class. __Example 5__ demonstrates how to do that. -###Example 5: Handle the propertyChange event via XML +需要注意的是,`propertyChange`事件对于整个[数据绑定]({% slug binding %})系统都是不安全的。如果要取得数据绑定机制的优势,你只需要让你的业务对象**继承(inherit)**自`Observable`类就可以了。__例5__ 示范了如何实现。 + +### Example 5: Handle the propertyChange event via XML + +### 例5:通过XML来处理propertyChange事件 ``` XML @@ -183,9 +271,15 @@ export function onCheckChange(args: PropertyChangeData) { console.log("value:" + args.value); } ``` + The code snippet in __Example 5__ fires the `propertyChange` event when the switch checked value is changed. -###Example 6: Creating a custom class and inheriting `Observable` class +__例5__ 中的代码片段在开关控件的checked值改变时触发`propertyChange`事件。 + +### Example 6: Creating a custom class and inheriting `Observable` class + +### 例6:创建继承自`Observable`的自定义类。 + ``` JavaScript var observableModule = require("data/observable"); var MyClass = (function (_super) { @@ -221,13 +315,23 @@ export class MyClass extends observableModule.Observable { } } ``` + The code snippet in __Example 6__ fires the `propertyChange` event when the property value is changed. +__例6__ 中的代码片段将会在指定属性的值改变时触发`propertyChange`事件。 + ## Creating a Custom Event -If your business logic demands it, you may want to fire (raise or emit) a custom event on a particular action (see __Example 7__). To do that, call the `Observable.notify()` method when the action is completed. This method takes any **implementer** of the [EventData interface](http://docs.nativescript.org/api-reference/interfaces/_data_observable_.eventdata.html) as event data. It includes basic information about an event—its name as `eventName` and an instance of the event sender as `object`). +## 创建自定义事件 + +If your business logic demands it, you may want to fire (raise or emit) a custom event on a particular action (see __Example 7__). To do that, call the `Observable.notify()` method when the action is completed. This method takes any **implementer** of the [EventData interface](http://docs.nativescript.org/api-reference/interfaces/_data_observable_.eventdata.html) as event data. It includes basic information about an event—its name as `eventName` and an instance of the event sender as `object`. + +如果业务逻辑需要触发(引发(raise)或发出(emit))针对特定操作的自定义事件(参考 __例7__),可以在该操作结束时调用`Observable.nofify()`方法。该方法接受任意[事件数据接口](http://docs.nativescript.org/api-reference/interfaces/_data_observable_.eventdata.html)的 **实现(implementer)** 来作为事件的数据。数据中将会包含该事件的基本信息—`eventName`键的键值是该事件的事件名;`object`键的键值是该事件的来源(event sender),是一个 `Observable` 类的实例。 + +### Example 7: Creating a custom event. + +### 例7:创建自定义事件。 -###Example 7: Creating a custom event. ``` JavaScript var eventData = { eventName: "myCustomEventName", @@ -242,34 +346,62 @@ var eventData: observableModule.EventData = { } this.notify(eventData); ``` + The minimum information needed to raise an event is the `eventName`—it will be used to execute all event handlers associated with this event. +引发(raise)事件至少需要提供`eventName`—用于执行所有和该事件关联的事件处理器。 + The next step is to hook to this event: +下一步就是挂接到这个事件上: + ``` JavaScript var myCustomObject = new MyClass(); myCustomObject.on("myCustomEventName", function(eventData){ console.log(eventData.eventName + " has been raised! by: " + eventData.object); }) ``` + A similar logic is implemented for the `propertyChange` event, so if your business logic requires that, `propertyChange` can be emitted manually through the `notify()` method (without using the `Observable.set()` method that also fires the `propertyChange` event). +`propertyChange`事件实现了类似的逻辑。因此,如果业务需要,可以通过`notify()`方法触发`propertyChange`事件(而不用使用`Observable.set()`方法来触发)。 + ## Avoiding Memory Leaks +## 避免内存泄漏 + Although the radio station comparison is convenient for understanding the concept, events are a bit more complicated on the inside. To be able to notify the listener, the sender contains a pointer to the listener. Even if you set the listener object to `null` or `undefined`, it is not eligible for garbage collection, because the sender is alive and has a live reference to the listener object. This could result in a memory leak when the object lifetimes of the sender and the listener differ significantly. +尽管使用电台做比喻能帮助对概念的理解,但是事件在内部实现上更复杂一点。为了能够通知监听器,发送器持有指向监听器的指针。因此即使你将监听器对象设置为`null`或者`undefined`,由于仍然存活的发送器中存在对它的引用,监听器对象将不符合垃圾回收器的回收条件。当发送器和监听器的生命周期相差很大时,就会导致内存泄漏。 + Consider this scenario: A UI element creates a lot of child controls, each of which hooks to an event of the parent. Then a child control is released (during a list view scrolling for instance), causing a memory leak. +设想这样一种场景:UI元素创建了许多子控件,每个控件都挂接到了父元素的某个事件上。随后,有一个子控件被释放了(比如在列表视图(list view)滚动时),于是导致了内存泄漏。 + To prevent these memory leaks, it is a good practice to remove your event listener handler before releasing the listener object. Unfortunately, sometimes you cannot determine the exact time to call the `off` or `removeEventListener` function. In such cases, use another option of the NativeScript framework: *weak events*. +为了防止这种内存泄漏,在释放监听器对象之前移除事件监听处理器是个好习惯。不幸的是,有时你无法确定调用`off`或者`removeEventListener`函数的合适时机。在这种情况下,可以使用NativeScript框架提供的另一种选项:*弱事件(weak events)*。 + ## Working with Weak Events +## 使用弱事件 + A weak event, as its name suggests, creates an weak reference to the listener object, which helps you release the listener object without removing the event listener pointer. +弱事件(Weak Events),顾名思义,将会创建到监听器对象的弱引用(weak reference)。这将帮助你在无需清除事件监听器指针的情况下释放监听对象。 + ### Adding a Weak Event Listener +### 增加弱事件监听器 + Using weak event listeners is very similar to normal events. __Example 8__ shows how to add a weak event listener (code comments are included for clarity): -###Example 8: Creating a weak event and handling a property change event + +弱事件监听器的用法和普通事件的很像。__例8__ 展示如何增加弱事件监听器(引入了使代码更清楚的注释): + +### Example 8: Creating a weak event and handling a property change event + +### 例8:创造弱事件并处理属性改变(property change)事件 + ``` JavaScript var weakEventListenerModule = require("ui/core/weak-event-listener"); var buttonModule = require("ui/button"); @@ -292,16 +424,22 @@ var handlePropertyChange = function () { var weakEL = weakEventListenerModule.WeakEventListener; var weakEventListenerOptions: weakEventListenerModule.WeakEventListenerOptions = { // create a weak reference to the event listener object + // 创建一个指向事件监听对象的弱引用变量。 targetWeakRef: new WeakRef(this), // create a weak reference to the event sender object + // 创建一个指向事件发送对象的弱引用变量。 sourceWeakRef: new WeakRef(this.source), // set the name of the event + // 设置事件的名称 eventName: observable.Observable.propertyChangeEvent, // set the event handler + // 设置事件处理器 handler: handlePropertyChange, - // (optional) set the context in which to execute the handler + // (optional) set the context in which to execute the handler + // (可选的)设置运行监听器的上下文 handlerContext: testButton, - // (optional) set a specialized property used for extra event recognition + // (optional) set a specialized property used for extra event recognition + // (可选的)设置专门的用于附加事件识别(recognition)的属性 key: this.options.targetProperty } weakEL.addWeakEventListener(this.weakEventListenerOptions); @@ -328,16 +466,22 @@ var handlePropertyChange = function () { var weakEL = weakEventListenerModule.WeakEventListener; var weakEventListenerOptions: weakEventListenerModule.WeakEventListenerOptions = { // create a weak reference to the event listener object + // 创建一个指向事件监听对象的弱引用变量。 targetWeakRef: new WeakRef(this), // create a weak reference to the event sender object + // 创建一个指向事件发送对象弱引用变量。 sourceWeakRef: new WeakRef(this.source), // set the name of the event + // 设置事件的名称 eventName: observable.Observable.propertyChangeEvent, // set the event handler + // 设置事件处理器 handler: handlePropertyChange, // specialized property used for extra event recognition + // 设置专门的用于附加事件识别的属性 key: this.options.targetProperty, // (optional) set the context in which to execute the handler + // (可选的)设置运行监听器的上下文 handlerContext: testButton } weakEL.addWeakEventListener(this.weakEventListenerOptions); @@ -345,10 +489,16 @@ weakEL.addWeakEventListener(this.weakEventListenerOptions); __Example 8__ shows how to attach a weak event listener to an observable object instance. A closer look at the `handlePropertyChange` function shows that `text` property of the `this` object is changed when the `propertyChange` event is raised (via the button tap event). The function demonstrates how to use the `handlerContext` property—its value is taken as an argument to `this` inside the event handler function. +__例8__ 展示了如何将弱事件监听器附着到可观测对象(observable object)的实例。细看`handlePropertyChange`函数,它的`this`对象的`text`属性在`propertyChange`事件(通过按钮触摸事件)引发时被改变了。该函数示范了如何使用`handlerContext`属性—它的值在事件处理器函数中被用作`this`参数。 + ### Removing a Weak Event Listener +### 移除弱事件监听器 + The `targetWeakRef` and `key` properties are optional when invoking a function on an event. However, they allow for removing an event listener. The properties are used as keys for a key-value pair that stores weak event listeners. +`targetWeakRef`和`key`属性在事件上调用函数时是可选的。然而,它们允许你移除事件监听器。这些属性被用作储存弱类型监听器的键-值对的键名。 + ``` JavaScript weakEL.removeWeakEventListener(this.weakEventListenerOptions); ```