翻译-微件开发

翻译自ArcGIS JS API 官网教程!!!

微件是可重用的用户界面组件,是提供丰富用户体验的关键。ArcGIS for JavaScript API提供了一组随时可用的微件。从4.2版开始,它还为创建定制微件提供了基础。

本指南讨论微件开发的基本原理。在当前框架下,它的实现仅关注特定领域。无论微件的功能是什么,创建自定义微件的基础都是一致的。这里有额外的资源 帮助您入门。可参考 Create custom widgetRecenter widget 的示例,了解如何创建自己的自定义微件。

请注意,这个框架并不打算替代所有dijit。使用dgrid就是一个这样的例子。在这里,您仍然需要使用Dijit。

开发前提

在创建自己的自定义微件之前,您需要确保具备所需的要求。这些将根据您的微件需求而变化。下面列出的是微件开发的最低要求。

TypeScript

TypeScript是JavaScript的超集。编写后它会被编译成纯JavaScript。微件开发建议使用TypeScript。这有一个额外的 TypeScript 启动 的例子,它提供了一些基础步骤来搭建你的TypeScript开发环境。这里有大量的网络资源 详细介绍TypeScript是什么,为什么使用和怎么使用它。熟悉这些基本知识将使微件开发过程更加容易。

JSX

JSX 是一种JavaScript扩展语法,它允许我们像描述HTML一样描述微件UI。它看起来类似于HTML,它可以与JavaScript内联使用。

熟悉esri/core/Accessor

Accessor 是4.x的核心特性之一,也是所有类(包括微件)的基类。关于它如何工作及其使用模式的更多细节,请参阅主题实现访问器

微件生命周期

在开始开发之前,一定要对微件的生命周期有个大致的了解。无论微件类型如何,其生命周期的一般概念都是相同的。它们是:

  1. constructor (params) - 这里是微件初始化时设置所需属性的地方。由于微件是从Accessor派生的,因此你可以在处理属性主题中了解获取、设置和查看属性。
  2. postInitialize() - 这个方法在微件被创建,但是UI还没有渲染的时候调用。
  3. render() - 这是唯一的一个必须方法,用来渲染UI。
  4. destroy() - 释放微件示例方法。

TypeScript装饰器

微件开发利用了 TypeScript装饰器。这允许我们在设计时定义和修改现有属性、方法和构造函数中的公共行为。我们将在下面讨论最常见的微件装饰器类型。

@subclass

可以将这些装饰器看作是用于创建类的底层粘合剂。

下面的代码片段导入并扩展了esri/widgets/Widget类,并在render方法中定义了UI。JSX用于定义UI。在这个简单的场景中,创建了一个内容为John Smith的div元素。

1
2
3
4
5
6
7
8
9
10
import Widget from "esri/widgets/Widget";

@subclass("esri.widgets.HelloWorld")
class HelloWorld extends Widget {
render() {
return (
<div>John Smith</div>
);
}
}

@property()

此装饰器用于定义访问器属性。使用这个装饰器定义的任何属性现在都可以获得和设置。此外,您还可以观察任何属性的更改。

1
2
@property()
name: string;

@renderable()

此装饰器用于调度渲染。每当修改属性时,都会自动调度和更新渲染。

1
2
@renderable()
name: string;

通常,在实现类属性时,您将同时使用@property()和@renderable()。例如,

1
2
3
@property()
@renderable()
name: string;

@aliasOf()

这个装饰器允许我们定义一个属性别名。这有助于保持代码的整洁,从而不重复现有的属性(例如,已经在ViewModel中实现了)。上面提供的完整示例没有使用此装饰器。如果有一个与该文件相关联的HelloWorldViewModel,则可以通过这种方法直接访问其属性,从而避免代码重复。

1
2
@aliasOf("viewModel.name")
name: string;

微件实施

以下步骤提供了实现自定义小部件所需步骤的高级概述:

继承微件

在非常基本的层次上,您将通过扩展基本的小部件类来创建小部件。

1
2
3
4
5
6
7
// Import used to extend off of base Widget class
import Widget from "esri/widgets/Widget";

@subclass("esri.widgets.HelloWorld")
class HelloWorld extends Widget {

}

实现属性和方法

接下来,您可以实现特定于该小部件的任何属性和/或方法。这段代码展示了如何利用这些属性的装饰器。

1
2
3
4
5
6
7
8
9
10
11
12
// Create 'name' property
@property()
@renderable()
name: string = "John Smith";

// Create 'emphasized' property
@property()
@renderable()
emphasized: boolean = false;

// Create private _onNameUpdate method
private _onNameUpdate(): string { return '${this.name}';}

默认情况下,元素中引用的函数将把 this 设置为实际元素。您可以选择使用bind属性来更新 this 。下面的代码绑定了监听 name 属性更新时使用的 _onNameUpdate 回调方法。这在下面的postInitialize方法中显示。

1
2
3
4
5
6
7
8
class HelloWorld extends Widget {

constructor() {
super();
this._onNameUpdate = this._onNameUpdate.bind(this);
}

}

postInitialize方法在微件的属性就绪时调用,但在它渲染之前调用。在下面的代码片段中,我们将观察name属性。一旦更新,它将调用_onNameUpdate回调方法。watchUtils.init()调用返回一个WatchHandle对象,然后将该对象传递给own()。这有助于在小部件被销毁后清理任何资源。

1
2
3
4
5
6
postInitialize() {
const handle = watchUtils.init(this, "name", this._onNameUpdate);

// Helper used for cleaning up resources once the widget is destroyed
this.own(handle);
}

渲染微件

在实现属性之后,使用JSX呈现微件的UI。这在微件的render方法中处理,这是微件实现所需的唯一方法。

有关此特性的额外信息,请参阅下面的 示例

请注意,作为JSX元素创建的小部件目前还不受支持。例如,以下代码片段将不起作用。

1
const search = <Search view={view} />;

微件CSS通过class属性设置。

1
2
3
4
5
6
7
8
9
render() {
const classes = { "hello-world-emphasized": this.emphasized };

return (
<div class = {this.classes("hello-world",classes)}>
{this._onNameUpdate()}
</div>
);
}

在4.7版本之前,如果需要更动态的方法,可以使用classes。这需要一个对象,其中键表示要切换的CSS类。如果值为true则添加该类,如果值为false则删除该类。

从4.7开始,不要使用此属性。而是使用classes helper方法。这个方法简化了CSS类属性的设置。

最后,在微件上调用destroy将释放微件,并释放在下面postInitialize中引用的own()方法中注册的所有资源。

1
2
3
4
5
6
postInitialize() {
const handle = watchUtils.init(this, "name", this._onNameUpdate);

// Helper used for cleaning up resources once the widget is destroyed
this.own(handle);
}

导出模块

在代码页的最后,添加一行以导出对象。

1
export default HelloWorld;

完成代码

创建自定义微件 示例完整地显示了.tsx文件。这个TypeScript文件使用这个扩展名来表示这个类使用JSX,e.g. .ts + .jsx = .tsx.

微件渲染

下面列出的属性可以用于渲染微件样式:

  • classes: (Deprecated at 4.7) This property allows CSS classes to be added and removed dynamically. Beginning with version 4.7, please use the classes helper method instead.
  • styles: Allows styles to be changed dynamically.
  • afterCreate: This callback method executes after the node is added to the DOM. Any child nodes and properties have already been applied. Use this method within render to access the real DOM node. It is also possible to use per element.
  • afterUpdate: This callback method executes every time the node is updated.
  • bind: This property is used to set the value of this for event handlers.
  • key: This is used to uniquely identify a DOM node among its siblings. This is important if you have sibling elements with the same selector and the elements are added/removed dynamically.

ViewModel模式

额外信息

请参阅这些额外的链接以获得更多信息: