ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# **事件** * Overview概览 * Adding an event handler添加一个事件处理器 * Removing an event listener移除事件监听器 * PropertyChange event属性变动 事件 * Creating a custom event创建自定义事件 * Avoiding memory leaks避免内存泄漏 * Working with weak events用弱事件工作 ## [**概览**](http://docs.nativescript.org/core-concepts/events#overview) 事件是从事件发射器发送的消息,以表示特定行为的发生。此行为可以由用户行为(如点击)或程序逻辑(例如,指示从服务器下载图像已完成)生成。引发事件的对象叫作**事件发送器**(简称**发送器**)或者**事件触发器**。消费事件的对象叫作**事件监听器**(简称**监听器**)或者**事件处理器**。 NativeScript框架提供了一个 `Observable` 类支持用事件工作的进程。有关这方面更多信息查看 [API Reference](http://docs.nativescript.org/api-reference/classes/_data_observable_.observable.html) 。因为这是NativeScript框架的基本类之一,几乎所有 NativeScript 对象(组件)都有处理事件的选项。 ## [**添加事件处理器**](http://docs.nativescript.org/core-concepts/events#adding-an-event-handler) 添加事件处理器意思是设置一个函数(方法),以在事件引发的时候执行。 **示例 1** 显示了如何设置一个函数,当按钮点击的时候在控制台打印输出“Hello World”。你可以在简化语法和完整语法中选择,或是可以在XML中声明一个事件处理器。 下面的例子显示了如何用简化语法和完整语法添加一个事件处理器。这里有个可选的第三个参数代表 `this` 参数。 ### [**示例1 \(JS\): 用简化和完整语法添加一个事件处理器或事件监听器**](http://docs.nativescript.org/core-concepts/events#example-1-javascript-adding-an-event-handler-or-an-event-listener-using-the-short-and-full-syntax) > `//Adding a listener with the short syntax简化语法` > > `var buttonModule = require("ui/button");` > > `var testButton = new buttonModule.Button();` > > `testButton.text = "Test";` > > `testButton.on(` > > `buttonModule.Button.tapEvent,` > > `function (eventData) { console.log("Hello World!"); },` > > `this` > > `);` > > `//Adding a lister with the full syntax完整语法` > > `var testButton2 = new buttonModule.Button();` > > `testButton2.text = "Test";` > > `var onTap = function (eventData) { console.log("Hello World!"); };` > > `testButton2.addEventListener(buttonModule.Button.tapEvent, onTap, this);` ### [**示例 1 \(XML\): 用XML声明添加事件处理器或事件监听器**](http://docs.nativescript.org/core-concepts/events#example-1-xml-adding-an-event-handler-or-an-event-listener-using-an-xml-declaration) > `<Page>` > > `<StackLayout>` > > `<Button tap="onTap" />` > > `</StackLayout>` > > `</Page>` 你需要一个后台代码文件(看示例2)来写函数体(后台代码文件有相同的文件名,但不同的后缀:.js或.ts,取决于你使用什么语言)。 ### [**示例 2: 关联按钮点击事件**](http://docs.nativescript.org/core-concepts/events#example-2-hooking-to-a-button-tap-event) > **JS** > > --- > > `function onTap(eventData) {` > > `console.log("Hello World!");` > > `}` > > `exports.onTap = onTap;` > > **TS** > > --- > > `export function onTap(eventData) {` > > `console.log("Hello World!");` > > `}` ## [**移除事件监听器**](http://docs.nativescript.org/core-concepts/events#removing-an-event-listener) 通常你没必要移除事件监听器。当你需要只接收一次事件或者释放资源时,你可以这样做。在此情况下,你可以使用**示例3**的方法。 > ### **没有语法来通过XML声明移除事件监听器。** ### **[示例 3: 移除按钮点击事件监听器](http://docs.nativescript.org/core-concepts/events#example-3-removing-a-button-tap-event-listener)** > **JS** > > --- > > `//Removing a listener with short syntax简单语法` > > `testButton.off(buttonModule.Button.tapEvent);` > > `//Removing a listener with full syntax完整语法` > > `testButton2.removeEventListener(buttonModule.Button.tapEvent);` ## [**属性变动事件**](http://docs.nativescript.org/core-concepts/events#propertychange-event) `Observable`类提供一个内置事件叫作 `propertyChange` ,当属性改变时该事件被调用。**示例4** 显示了如何订阅该事件。 ### **示例 4: 处理 propertyChange 事件** > ### JS > > --- > > `var observableModule = require("data/observable");` > > `var observableObject = new observableModule.Observable();` > > `observableObject.on(` > > `observableModule.Observable.propertyChangeEvent,` > > `function(propertyChangeData){` > > `console.log(propertyChangeData.propertyName + " has been changed and the new value is: " + propertyChangeData.value);` > > `}` > > `);` 这里主要的是要注意 `propertyChange` 事件对整个数据绑定系统是至关重要的。要充分利用数据绑定机制,你必须要做的是让你的业务对象继承 `Observable` 类。**示例5**演示了如何做到这点。 ### **示例5: 通过XML处理propertyChange事件** > **XML** > > --- > > `<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo">` > > `<StackLayout>` > > `<Switch checked="" propertyChange="onCheckChange"/>` > > `</StackLayout>` > > `</Page>` > > **JS** > > --- > > `function onCheckChange(args) {` > > `console.log("Property Changed!");` > > `console.log("Event name:" + args.eventName);` > > `console.log("Object:" + args.object);` > > `console.log("propertyname:" + args.propertyName);` > > `console.log("value:" + args.value);` > > `}` > > `exports.onCheckChange = onCheckChange;` 当 `switch` 选择的值变化时(也就是点击 switch 按钮切换时) ,触发示例5代码片段里的 `propertyChange` 事件。 ### **示例 6: 创建自定义类并继承**`Observable`**类** > **JS** > > --- > > `var observableModule = require("data/observable");` > > `var MyClass = (function (_super) {` > > `__extends(MyClass, _super);` > > `function MyClass() { _super.apply(this, arguments); }` > > `Object.defineProperty(` > > `MyClass.prototype,` > > `"myProperty",` > > `{` > > `get: function () { return this._myProperty; },` > > `set: function (value) { this._myProperty = value; },` > > `enumerable: true,` > > `configurable: true` > > `}` > > `); return MyClass;` > > `})(observableModule.Observable);` > > `exports.MyClass = MyClass;` 当属性值改变时, 触发示例6代码片段里的 `propertyChange`事件。 ## **[创建自定义事件](http://docs.nativescript.org/core-concepts/events#creating-a-custom-event)** 如果你的业务逻辑需要,你可能想要在特别的行为上触发(引发或发出)一个自定义事件(参看**示例7**)。为此,当该行为完成时调用 ```Obser``vable.notify()``` 方法。该方法取得 [EventData 接口](http://docs.nativescript.org/api-reference/interfaces/_data_observable_.eventdata.html) 的任何实施者作为事件数据。这包括有关一个事件的基本信息—— 它的名字作为 `eventName` ,且事件发送器的一个实例作为 `object` 。 ### [**示例 7: 创建自定义事件**](http://docs.nativescript.org/core-concepts/events#example-7-creating-a-custom-event) > **JS** > > --- > > `var eventData = {` > > `eventName: "myCustomEventName",` > > `object: this` > > `};` > > `this.notify(eventData);` 引发一个事件的最少必要信息是 `eventName` ——它将被用来执行与此事件相关联的所有事件处理器。 下一步是关联到该事件: > `var myCustomObject = new MyClass();` > > `myCustomObject.on(` > > `"myCustomEventName",` > > `function(eventData){ console.log(eventData.eventName + " has been raised! by: " + eventData.object); }` > > `)` 类似的逻辑是实现 `propertyChange` 事件,所以如果你的业务逻辑要求这样, `propertyChange` 可以手动通过 ```notify``()``` 方法发出的(不使用 `Observable.set()` 方法也可以触发 `propertyChange` 事件)。 ## [**避免内存泄漏**](http://docs.nativescript.org/core-concepts/events#avoiding-memory-leaks) 虽然无线电台的比较便于理解这个概念,但事件内部有一点复杂。为了能够通知监听器,发送器包含一个指向监听器的指针。即使你将监听器对象设置为 `null` 或 `undefined` ,它也不符合垃圾回收的条件,因为发送者是活的,并对监听器对象有一个实时引用。当发送者和听者的对象生存期存在显著差异时, 这可能会导致在内存泄漏。 考虑这个场景:一个UI元素创建了一大堆子控件,每个都关联到一个父元素的事件。然后释放一个子控件(在列表视图滚动的情况下),会引起内存泄漏。 要避免这些内存泄漏,比较好的实践是释放监听器对象之前移除监听器的处理器。不幸的是,有时你不能确定调用 `off` 或 `removeEventListener` 函数的具体时间。在此情况下,使用 NativeScript 框架的另一个选项: **_弱事件_** 。 ## **[使用 Weak Events](http://docs.nativescript.org/core-concepts/events#working-with-weak-events)** 一个弱事件,就像其名字表露的,创建一个监听器对象的弱引用。它会帮你释放监听器对象而不用移除监听器指针。 ### **[添加弱事件监听器](http://docs.nativescript.org/core-concepts/events#working-with-weak-events-Adding)** 使用弱事件监听器和普通事件非常类似。**示例8**显示了如何添加一个弱事件监听器(为了清晰包括了代码注释): ### **[示例 8: 创建弱事件并 处理 property change 事件](http://docs.nativescript.org/core-concepts/events#working-with-weak-events-Example)** > **JS** > > --- > > `var weakEventListenerModule = require("ui/core/weak-event-listener");` > > `var buttonModule = require("ui/button");` > > `var observableModule = require("data/observable");` > > `var testButton = new buttonModule.Button();` > > `testButton.text = "Test";` > > `testButton.on(buttonModule.Button.tapEvent, function () { source.set("testProperty", "change" + counter); });` > > `var source = new observableModule.Observable();` > > `var counter = 0;` > > `var handlePropertyChange = function () { counter++; this.text = counter + ""; };` > > `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` > > `handlerContext: testButton,` > > `// (optional) set a specialized property used for extra event recognition` > > `key: this.options.targetProperty` > > `}` > > `weakEL.addWeakEventListener(this.weakEventListenerOptions);` 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 对象实例。仔细看看 `handlePropertyChange` 函数,显示了当 `propertyChange` 事件触发时(通过点击事件), `this` 对象的 `text` 属性变化。该函数演示了如何使用 `handlerContext` 属性——在事件处理器内部,它的值被拿去当作 `this` 的一个参数。 ### **[移除弱事件](http://docs.nativescript.org/core-concepts/events#working-with-weak-events-Removing)** 在事件触发调用一个函数之时, `targetWeakRef` 和 `key` 属性是可选的。然而,他们允许移除事件监听器。这些属性被用作键值对的键(key)来保存弱事件监听器。 > **JS** > > --- > > `weakEL.removeWeakEventListener(this.weakEventListenerOptions);`