@geodaoyu/accessor 1.0.2 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +224 -145
- package/dist/accessor.d.ts +16 -2
- package/dist/accessor.js +89 -103
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/package.json +10 -3
- package/src/accessor.ts +119 -122
- package/src/index.ts +1 -1
- package/test/construct.test.js +0 -31
- package/test/get.test.js +0 -34
- package/test/set.test.js +0 -56
- package/test/watch.test.js +0 -168
- package/tsconfig.json +0 -18
package/README.md
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
# Accessor
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Overview
|
|
4
4
|
|
|
5
5
|
Accessor is an abstract class that facilitates the access to instance properties as well as a mechanism to watch for property changes. Every sub-class of Accessor defines properties that are directly accessible or by using the **get()** and **set()** methods. It is possible to watch for a property changes by using the **watch()** method.
|
|
6
6
|
|
|
7
|
-
## Installation
|
|
8
|
-
|
|
9
|
-
``` shell
|
|
10
|
-
npm install @geodaoyu/accessor
|
|
11
|
-
```
|
|
12
|
-
|
|
13
7
|
## Property Overview
|
|
14
8
|
|
|
15
9
|
| Name | Type | Summary | Class |
|
|
@@ -24,46 +18,13 @@ The name of the class.
|
|
|
24
18
|
|
|
25
19
|
## Method Overview
|
|
26
20
|
|
|
27
|
-
| Name
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
| set() | * | Sets the value of a property. | Accessor |
|
|
31
|
-
| watch() | WatchHandle | Watches for property changes on the instance. | Accessor |
|
|
21
|
+
| Name | Return Type | Summary | Class |
|
|
22
|
+
| ----- | ----------- | ----------------------------- | -------- |
|
|
23
|
+
| set() | * | Sets the value of a property. | Accessor |
|
|
32
24
|
|
|
33
25
|
### Method Details
|
|
34
26
|
|
|
35
|
-
<table><tr><td bgcolor=#ddd><b>
|
|
36
|
-
|
|
37
|
-
Gets the value of a property.
|
|
38
|
-
|
|
39
|
-
The name of the property can refer to a property in the instance.
|
|
40
|
-
|
|
41
|
-
```javascript
|
|
42
|
-
view.get("scale");
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
It can also be a path to a property deeper in the instance. `get()` returns `undefined` if a property in the path doesn't exist.
|
|
46
|
-
|
|
47
|
-
```javascript
|
|
48
|
-
var title = map.get("basemap.title");
|
|
49
|
-
|
|
50
|
-
// equivalent of
|
|
51
|
-
var title = map.basemap && map.basemap.title || undefined;
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Parameter:
|
|
55
|
-
|
|
56
|
-
| **path** | [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) |
|
|
57
|
-
| -------------------------------- | ------------------------------------------------------------ |
|
|
58
|
-
| The path of the property to get. | |
|
|
59
|
-
|
|
60
|
-
Returns:
|
|
61
|
-
|
|
62
|
-
| Type | Description |
|
|
63
|
-
| ---- | --------------------- |
|
|
64
|
-
| * | The property's value. |
|
|
65
|
-
|
|
66
|
-
<table><tr><td bgcolor=#ddd><b>set(path, value){*}</b></td></tr></table>
|
|
27
|
+
<table><tr><td bgcolor=#ddd><b>set(path, value) {*}</b></td></tr></table>
|
|
67
28
|
|
|
68
29
|
Sets the value of a property.
|
|
69
30
|
|
|
@@ -76,7 +37,7 @@ map.set("basemap", "topo-vector");
|
|
|
76
37
|
map.basemap = "topo-vector";
|
|
77
38
|
|
|
78
39
|
// currying set
|
|
79
|
-
|
|
40
|
+
const updateViewScale = view.set.bind(view, "scale");
|
|
80
41
|
updateViewScale(5000);
|
|
81
42
|
```
|
|
82
43
|
|
|
@@ -102,7 +63,7 @@ view.set({
|
|
|
102
63
|
});
|
|
103
64
|
|
|
104
65
|
// currying set
|
|
105
|
-
|
|
66
|
+
const updateView = view.set.bind(view);
|
|
106
67
|
|
|
107
68
|
updateView({
|
|
108
69
|
center: [-4.4861, 48.3904],
|
|
@@ -116,7 +77,7 @@ updateView({
|
|
|
116
77
|
| ------------------------------------------------------------ | ------------------------------------------------------------ |
|
|
117
78
|
| The path to the property to set, or an object of key-value pairs. | |
|
|
118
79
|
| **value** | * |
|
|
119
|
-
|
|
|
80
|
+
| The new value to set on the property. | |
|
|
120
81
|
|
|
121
82
|
Returns:
|
|
122
83
|
|
|
@@ -124,116 +85,139 @@ Returns:
|
|
|
124
85
|
| ---- | ------------- |
|
|
125
86
|
| * | The instance. |
|
|
126
87
|
|
|
127
|
-
|
|
88
|
+
# reactiveUtils
|
|
128
89
|
|
|
129
|
-
|
|
90
|
+
## Overview
|
|
130
91
|
|
|
131
|
-
|
|
92
|
+
`reactiveUtils` provide capabilities for observing changes to the state of the SDK's properties, and is an important part of managing your application's life-cycle. State can be observed on a variety of different data types and structures including strings, numbers, arrays, booleans, collections, and objects.
|
|
132
93
|
|
|
133
|
-
|
|
134
|
-
var handle = mapview.watch("scale", function(newValue, oldValue, propertyName, target) {
|
|
135
|
-
console.log(propertyName + " changed from " + oldValue + " to " + newValue);
|
|
136
|
-
})
|
|
137
|
-
```
|
|
94
|
+
## Using reactiveUtils
|
|
138
95
|
|
|
139
|
-
|
|
96
|
+
`reactiveUtils` provides five methods that offer different patterns and capabilities for observing state: [on()](https://developers.arcgis.com/javascript/latest/api-reference/esri-core-reactiveUtils.html#on), [once()](https://developers.arcgis.com/javascript/latest/api-reference/esri-core-reactiveUtils.html#once), [watch()](https://developers.arcgis.com/javascript/latest/api-reference/esri-core-reactiveUtils.html#watch), [when()](https://developers.arcgis.com/javascript/latest/api-reference/esri-core-reactiveUtils.html#when) and [whenOnce()](https://developers.arcgis.com/javascript/latest/api-reference/esri-core-reactiveUtils.html#whenOnce).
|
|
97
|
+
|
|
98
|
+
The following is a basic example using [reactiveUtils.watch()](https://developers.arcgis.com/javascript/latest/api-reference/esri-core-reactiveUtils.html#watch). It demonstrates how to track the Map component [updating](https://developers.arcgis.com/javascript/latest/references/map-components/arcgis-map/#updating) property and then send a message to the console when the property changes. This snippet uses a `getValue` function as an expression that evaluates the `updating` property, and when a change is observed the new value is passed to the callback:
|
|
140
99
|
|
|
141
|
-
```
|
|
142
|
-
|
|
100
|
+
```
|
|
101
|
+
// Basic example of watching for changes on a boolean property
|
|
102
|
+
const viewElement = document.querySelector("arcgis-map");
|
|
103
|
+
reactiveUtils.watch(
|
|
104
|
+
// getValue function
|
|
105
|
+
() => viewElement.updating,
|
|
106
|
+
// callback
|
|
107
|
+
(updating) => {
|
|
108
|
+
console.log(updating)
|
|
109
|
+
});
|
|
143
110
|
```
|
|
144
111
|
|
|
145
|
-
It is important to store the resulting objects from `watch()` to properly clean up the references.
|
|
146
112
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
113
|
+
|
|
114
|
+
### Working with collections
|
|
115
|
+
|
|
116
|
+
`reactiveUtils` can be used to observe changes within a collection, such as [Map.allLayers](https://developers.arcgis.com/javascript/latest/api-reference/esri-Map.html#allLayers). Out-of-the-box JavaScript methods such as [`.map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) and [`.filter()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) can be used as expressions to be evaluated in the `getValue` function.
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
// Watching for changes within a collection
|
|
120
|
+
// whenever a new layer is added to the map
|
|
121
|
+
const viewElement = document.querySelector("arcgis-map");
|
|
122
|
+
reactiveUtils.watch(
|
|
123
|
+
() => viewElement.map.allLayers.map( layer => layer.id),
|
|
124
|
+
(ids) => {
|
|
125
|
+
console.log(`FeatureLayer IDs ${ids}`);
|
|
153
126
|
});
|
|
154
|
-
|
|
127
|
+
```
|
|
155
128
|
|
|
156
|
-
this.view = view;
|
|
157
129
|
|
|
158
|
-
// watch for properties on the newly set view.
|
|
159
|
-
if (view) {
|
|
160
|
-
viewHandles.push(
|
|
161
|
-
view.watch("scale", scaleWatcher);
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
130
|
|
|
166
|
-
|
|
167
|
-
|
|
131
|
+
### Working with objects
|
|
132
|
+
|
|
133
|
+
With `reactiveUtils` you can track named object properties through dot notation (e.g. `viewElement.updating`) or through bracket notation (e.g. `viewElement["updating"]`). You can also use the [optional chaining](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) operator (`?.`). This operator simplifies the process of verifying that properties used in the `getValue` function are not `undefined` or `null`.
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
// Watch for changes in an object using optional chaining
|
|
137
|
+
// whenever the map's extent changes
|
|
138
|
+
const viewElement = document.querySelector("arcgis-map");
|
|
139
|
+
reactiveUtils.watch(
|
|
140
|
+
() => viewElement?.extent?.xmin,
|
|
141
|
+
(xmin) => {
|
|
142
|
+
console.log(`Extent change xmin = ${xmin}`)
|
|
143
|
+
});
|
|
168
144
|
```
|
|
169
145
|
|
|
170
|
-
Like `get()` and `set()`, it is possible to watch for a property deep in the object hierarchy by passing a path. If a property in the path doesn't exist the watch callback is called with `undefined`.
|
|
171
146
|
|
|
172
|
-
``` javascript
|
|
173
|
-
var view = new SceneView({
|
|
174
|
-
map: new Map({
|
|
175
|
-
basemap: "streets-vector"
|
|
176
|
-
})
|
|
177
|
-
});
|
|
178
147
|
|
|
179
|
-
|
|
180
|
-
console.log("basemap's title changed from " + oldValue + " to " + newValue);
|
|
181
|
-
});
|
|
148
|
+
### WatchHandles and Promises
|
|
182
149
|
|
|
183
|
-
|
|
184
|
-
// output: "basemap's title changed from Streets to Topographic"
|
|
150
|
+
The [watch()](https://developers.arcgis.com/javascript/latest/api-reference/esri-core-reactiveUtils.html#watch), [on()](https://developers.arcgis.com/javascript/latest/api-reference/esri-core-reactiveUtils.html#on) and [when()](https://developers.arcgis.com/javascript/latest/api-reference/esri-core-reactiveUtils.html#when) methods return a [WatchHandle](https://developers.arcgis.com/javascript/latest/api-reference/esri-core-Accessor.html#WatchHandle). Be sure to remove watch handles when they are no longer needed to avoid memory leaks.
|
|
185
151
|
|
|
186
|
-
view.map = null;
|
|
187
|
-
// output: "basemap's title changed from Topographic to undefined"
|
|
188
152
|
```
|
|
153
|
+
// Use a WatchHandle to stop watching
|
|
154
|
+
const viewElement = document.querySelector("arcgis-map");
|
|
155
|
+
const handle = reactiveUtils.watch(
|
|
156
|
+
() => viewElement?.extent?.xmin,
|
|
157
|
+
(xmin) => {
|
|
158
|
+
console.log(`Extent change xmin = ${xmin}`)
|
|
159
|
+
});
|
|
189
160
|
|
|
190
|
-
|
|
161
|
+
// In another function
|
|
162
|
+
handle.remove()
|
|
163
|
+
```
|
|
191
164
|
|
|
192
|
-
|
|
193
|
-
view.watch("center, scale, rotation", function(newValue, oldValue, propertyName) {
|
|
194
|
-
console.log(propertyName + " changed");
|
|
195
|
-
});
|
|
165
|
+
The [once()](https://developers.arcgis.com/javascript/latest/api-reference/esri-core-reactiveUtils.html#once) and [whenOnce()](https://developers.arcgis.com/javascript/latest/api-reference/esri-core-reactiveUtils.html#whenOnce) methods return a Promise instead of a `WatchHandle`. In some advanced use cases where an API action may take additional time, these methods also offer the option to cancel the async callback via an [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController/signal). Be aware that if the returned Promise is not resolved, it can also result in a memory leak.
|
|
196
166
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
167
|
+
```
|
|
168
|
+
// Use an AbortSignal to cancel an async callback
|
|
169
|
+
// during view animation
|
|
170
|
+
const abortController = new AbortController();
|
|
171
|
+
|
|
172
|
+
// Observe the View's animation state
|
|
173
|
+
reactiveUtils.whenOnce(
|
|
174
|
+
() => view?.animation, {signal: abortController.signal})
|
|
175
|
+
.then((animation) => {
|
|
176
|
+
console.log(`View animation state is ${animation.state}`)
|
|
177
|
+
});
|
|
201
178
|
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
|
|
179
|
+
// Cancel the async callback
|
|
180
|
+
const someFunction = () => {
|
|
181
|
+
abortController.abort();
|
|
205
182
|
}
|
|
206
|
-
view.watch("center", callback);
|
|
207
|
-
view.watch("scale", callback);
|
|
208
|
-
view.watch("rotation", callback);
|
|
209
183
|
```
|
|
210
184
|
|
|
211
|
-
`Accessor` doesn't call the watch callbacks for a property immediately after its value changes. Instead, when a property's value changes and if that property is watched, `Accessor` schedules a notification which is then processed at a later time. Properties that change frequently like `view.scale` can be watched without having to throttle the callback.
|
|
212
185
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
console.log("current view scale: " + view.scale);
|
|
219
|
-
view.scale = view.scale / 2;
|
|
220
|
-
view.scale = view.scale / 2;
|
|
221
|
-
view.scale = view.scale / 2;
|
|
222
|
-
console.log("current view scale: " + view.scale);
|
|
223
|
-
|
|
224
|
-
// output the following:
|
|
225
|
-
// current view scale: 36978595.474472
|
|
226
|
-
// current view scale: 4622324.434309
|
|
227
|
-
// view's scale changed from 36978595.474472 to 4622324.434309
|
|
186
|
+
|
|
187
|
+
### Working with truthy values
|
|
188
|
+
|
|
189
|
+
The [when()](https://developers.arcgis.com/javascript/latest/api-reference/esri-core-reactiveUtils.html#when) and [whenOnce()](https://developers.arcgis.com/javascript/latest/api-reference/esri-core-reactiveUtils.html#whenOnce) methods watch for *truthy* values, these are values that evaluate to `true` in boolean contexts. To learn more about using truthy, visit this [MDN Web doc](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) article. The snippets below use the [Popup.visible](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Popup.html) property, which is a boolean.
|
|
190
|
+
|
|
228
191
|
```
|
|
192
|
+
// Observe changes on a boolean property
|
|
193
|
+
const viewElement = document.querySelector("arcgis-map");
|
|
194
|
+
reactiveUtils.when(() => viewElement.popup?.visible, () => console.log("Truthy"));
|
|
195
|
+
reactiveUtils.when(() => !viewElement.popup?.visible, () => console.log("Not truthy"));
|
|
196
|
+
reactiveUtils.when(() => viewElement.popup?.visible === true, () => console.log("True"));
|
|
197
|
+
reactiveUtils.when(() => viewElement.popup?.visible !== undefined, () => console.log("Defined"));
|
|
198
|
+
reactiveUtils.when(() => viewElement.popup?.visible === undefined, () => console.log("Undefined"));
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Method Overview
|
|
202
|
+
|
|
203
|
+
| Name | Return Type | Summary | Object |
|
|
204
|
+
| ------- | ----------- | ------------------------------------------------------------ | ------------- |
|
|
205
|
+
| watch() | WatchHandle | Tracks any properties accessed in the `getValue` function and calls the callback when any of them change. | reactiveUtils |
|
|
206
|
+
|
|
207
|
+
### Method Details
|
|
208
|
+
<table><tr><td bgcolor=#ddd><b>watch(getValue, callback, options?){WatchHandle}</b></td></tr></table>
|
|
209
|
+
|
|
210
|
+
Tracks any properties accessed in the `getValue` function and calls the callback when any of them change.
|
|
229
211
|
|
|
230
212
|
Parameters:
|
|
231
213
|
|
|
232
|
-
| **
|
|
233
|
-
| ------------------------------------------------------------ |
|
|
234
|
-
|
|
|
235
|
-
| **callback** |
|
|
236
|
-
| The
|
|
214
|
+
| **getValue** | ReactiveWatchExpression |
|
|
215
|
+
| ------------------------------------------------------------ | ------------------------- |
|
|
216
|
+
| Function used to get the current value. All accessed properties will be tracked. | |
|
|
217
|
+
| **callback** | **ReactiveWatchCallback** |
|
|
218
|
+
| The function to call when there are changes. | |
|
|
219
|
+
| **options** | **ReactiveWatchOptions** |
|
|
220
|
+
| Options used to configure how the tracking happens and how the callback is to be called. | |
|
|
237
221
|
|
|
238
222
|
Returns:
|
|
239
223
|
|
|
@@ -241,27 +225,55 @@ Returns:
|
|
|
241
225
|
| ----------- | -------------- |
|
|
242
226
|
| WatchHandle | A watch handle |
|
|
243
227
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
228
|
+
Examples
|
|
229
|
+
|
|
230
|
+
```js
|
|
231
|
+
// Watching for changes in a boolean value
|
|
232
|
+
// Equivalent to watchUtils.watch()
|
|
233
|
+
const viewElement = document.querySelector("arcgis-map");
|
|
234
|
+
reactiveUtils.watch(
|
|
235
|
+
() => viewElement.popup?.visible,
|
|
236
|
+
() => {
|
|
237
|
+
console.log(`Popup visible: ${viewElement.popup.visible}`);
|
|
238
|
+
});
|
|
239
|
+
// Watching for changes within a Collection
|
|
240
|
+
const viewElement = document.querySelector("arcgis-map");
|
|
241
|
+
reactiveUtils.watch(
|
|
242
|
+
() => viewElement.map.allLayers.length,
|
|
243
|
+
() => {
|
|
244
|
+
console.log(`Layer collection length changed: ${viewElement.map.allLayers.length}`);
|
|
245
|
+
});
|
|
246
|
+
// Watch for changes in a numerical value.
|
|
247
|
+
// Providing `initial: true` in ReactiveWatchOptions
|
|
248
|
+
// checks immediately after initialization
|
|
249
|
+
// Equivalent to watchUtils.init()
|
|
250
|
+
const viewElement = document.querySelector("arcgis-map");
|
|
251
|
+
reactiveUtils.watch(
|
|
252
|
+
() => viewElement.zoom,
|
|
253
|
+
() => {
|
|
254
|
+
console.log(`zoom changed to ${viewElement.zoom}`);
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
initial: true
|
|
258
|
+
});
|
|
259
|
+
// Watch properties from multiple sources
|
|
260
|
+
const viewElement = document.querySelector("arcgis-map");
|
|
261
|
+
const handle = reactiveUtils.watch(
|
|
262
|
+
() => [viewElement.stationary, viewElement.zoom],
|
|
263
|
+
([stationary, zoom]) => {
|
|
264
|
+
// Only print the new zoom value when the map component is stationary
|
|
265
|
+
if(stationary){
|
|
266
|
+
console.log(`Change in zoom level: ${zoom}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
);
|
|
270
|
+
```
|
|
251
271
|
|
|
252
|
-
|
|
253
|
-
| ------------------------------------------------- | ------------------------------------------------------------ |
|
|
254
|
-
| The new value of the watched property. | |
|
|
255
|
-
| **oldValue** | * |
|
|
256
|
-
| The old value of the watched property. | |
|
|
257
|
-
| **propertyName** | [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) |
|
|
258
|
-
| The property name. | |
|
|
259
|
-
| **target** | Accessor |
|
|
260
|
-
| The object containing the property being watched. | |
|
|
272
|
+
## Type Definitions
|
|
261
273
|
|
|
262
274
|
<table><tr><td bgcolor=#ddd><b>WatchHandle</b> <span>Object</span></td></tr></table>
|
|
263
275
|
|
|
264
|
-
Represents a watch
|
|
276
|
+
Represents a watch or event handler which can be removed.
|
|
265
277
|
|
|
266
278
|
Property:
|
|
267
279
|
|
|
@@ -272,11 +284,78 @@ Property:
|
|
|
272
284
|
Example:
|
|
273
285
|
|
|
274
286
|
``` javascript
|
|
275
|
-
|
|
287
|
+
const handle = reactiveUtils.watch(() => map.basemap, (newVal) => {
|
|
276
288
|
// Each time the value of map.basemap changes, it is logged in the console
|
|
277
289
|
console.log("new basemap: ", newVal);
|
|
278
290
|
});
|
|
279
291
|
|
|
280
292
|
// When remove() is called on the watch handle, the map no longer watches for changes to basemap
|
|
281
293
|
handle.remove();
|
|
282
|
-
```
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
<table><tr><td bgcolor=#ddd><b>ReactiveEqualityFunction(newValue, oldValue) {Boolean}</b></td></tr></table>
|
|
297
|
+
|
|
298
|
+
Function used to check whether two values are the same, in which case the watch callback isn't called.
|
|
299
|
+
|
|
300
|
+
Parameters:
|
|
301
|
+
|
|
302
|
+
| **newValue** | * |
|
|
303
|
+
| -------------- | ---- |
|
|
304
|
+
| The new value. | |
|
|
305
|
+
| **oldValue** | * |
|
|
306
|
+
| The old value. | |
|
|
307
|
+
|
|
308
|
+
Returns:
|
|
309
|
+
|
|
310
|
+
| Type | Description |
|
|
311
|
+
| ------- | ------------------------------------------------ |
|
|
312
|
+
| Boolean | Whether the new value is equal to the old value. |
|
|
313
|
+
|
|
314
|
+
<table><tr><td bgcolor=#ddd><b>ReactiveListenerChangeCallback(target?)</b></td></tr></table>
|
|
315
|
+
|
|
316
|
+
Function used to check whether two values are the same, in which case the watch callback isn't called.
|
|
317
|
+
|
|
318
|
+
Parameters:
|
|
319
|
+
|
|
320
|
+
| **target** | * |
|
|
321
|
+
| ------------------------------------------------------------ | ---- |
|
|
322
|
+
| The event target to which the listener was added or from which it was removed. | |
|
|
323
|
+
|
|
324
|
+
<table><tr><td bgcolor=#ddd><b>ReactiveWatchCallback(newValue, oldValue) {Boolean}</b></td></tr></table>
|
|
325
|
+
|
|
326
|
+
Function to be called when a value changes.
|
|
327
|
+
|
|
328
|
+
Parameters:
|
|
329
|
+
|
|
330
|
+
| **newValue** | * |
|
|
331
|
+
| -------------- | ---- |
|
|
332
|
+
| The new value. | |
|
|
333
|
+
| **oldValue** | * |
|
|
334
|
+
| The old value. | |
|
|
335
|
+
|
|
336
|
+
<table><tr><td bgcolor=#ddd><b>ReactiveWatchExpression(){*}</b></td></tr></table>
|
|
337
|
+
|
|
338
|
+
Function which is auto-tracked and should return a value to pass to the ReactiveWatchCallback
|
|
339
|
+
|
|
340
|
+
Returns:
|
|
341
|
+
|
|
342
|
+
| Type | Description |
|
|
343
|
+
| ---- | -------------- |
|
|
344
|
+
| * | The new value. |
|
|
345
|
+
|
|
346
|
+
<table><tr><td bgcolor=#ddd><b>ReactiveWatchOptions</b> <span>Object</span></td></tr></table>
|
|
347
|
+
|
|
348
|
+
Options used to configure how auto-tracking is performed and how the callback should be called.
|
|
349
|
+
|
|
350
|
+
Property:
|
|
351
|
+
|
|
352
|
+
| **initial** | Boolean |
|
|
353
|
+
| ------------------------------------------------------------ | ---------------------------- |
|
|
354
|
+
| Default Value:false<br />Whether to fire the callback immediately after initialization, if the necessary conditions are met. | |
|
|
355
|
+
| **sync** | **Boolean** |
|
|
356
|
+
| Default Value:false<br />Whether to fire the callback synchronously or on the next tick. | |
|
|
357
|
+
| **once** | **Boolean** |
|
|
358
|
+
| Default Value:false<br />Whether to fire the callback only once. | |
|
|
359
|
+
| **equals** | **ReactiveEqualityFunction** |
|
|
360
|
+
| Function used to check whether two values are the same, in which case the callback isn't called. Checks whether two objects, arrays or primitive values are shallow equal, e.g. one level deep. Non-plain objects are considered equal if they are strictly equal (===). | |
|
|
361
|
+
|
package/dist/accessor.d.ts
CHANGED
|
@@ -1,2 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
type WatchCallback = (newValue: any, oldValue: any, propertyName: string, target: Accessor) => void;
|
|
2
|
+
interface WatchHandle extends Object {
|
|
3
|
+
/**
|
|
4
|
+
* Removes the watch handle.
|
|
5
|
+
*/
|
|
6
|
+
remove(): void;
|
|
7
|
+
}
|
|
8
|
+
declare class Accessor {
|
|
9
|
+
declaredClass: string;
|
|
10
|
+
private _handles;
|
|
11
|
+
constructor(props?: object);
|
|
12
|
+
get(path: string): any;
|
|
13
|
+
set(path: string | object, value: any): this;
|
|
14
|
+
watch(path: string | string[], callback: WatchCallback): WatchHandle;
|
|
15
|
+
}
|
|
16
|
+
export default Accessor;
|
package/dist/accessor.js
CHANGED
|
@@ -1,103 +1,89 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
this[
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
handles.push(handle);
|
|
91
|
-
this._handles.add(handle);
|
|
92
|
-
});
|
|
93
|
-
const watchHandle = {
|
|
94
|
-
remove: () => {
|
|
95
|
-
handles.forEach((handle) => {
|
|
96
|
-
this._handles.delete(handle);
|
|
97
|
-
});
|
|
98
|
-
},
|
|
99
|
-
};
|
|
100
|
-
return watchHandle;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
export default observe(Accessor);
|
|
1
|
+
class Accessor {
|
|
2
|
+
declaredClass;
|
|
3
|
+
_handles;
|
|
4
|
+
constructor(props = {}) {
|
|
5
|
+
// 为当前实例创建一个代理
|
|
6
|
+
const proxy = new Proxy(this, {
|
|
7
|
+
set: (target, key, value, receiver) => {
|
|
8
|
+
if (key !== '_handles' && target._handles) {
|
|
9
|
+
const oldValue = target[key];
|
|
10
|
+
target._handles.forEach((handle) => {
|
|
11
|
+
if (handle.path === key) {
|
|
12
|
+
handle.callback(value, oldValue, key, target);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return Reflect.set(target, key, value, receiver);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
// 初始化属性
|
|
20
|
+
for (let prop in props) {
|
|
21
|
+
proxy[prop] = props[prop];
|
|
22
|
+
}
|
|
23
|
+
proxy.declaredClass = "Accessor";
|
|
24
|
+
proxy._handles = new Set();
|
|
25
|
+
return proxy;
|
|
26
|
+
}
|
|
27
|
+
get(path) {
|
|
28
|
+
const dotIndex = path.indexOf(".");
|
|
29
|
+
if (dotIndex !== -1) {
|
|
30
|
+
const key = path.slice(0, dotIndex);
|
|
31
|
+
const value = path.slice(dotIndex + 1);
|
|
32
|
+
return this[key] && this[key].get(value);
|
|
33
|
+
}
|
|
34
|
+
return this[path];
|
|
35
|
+
}
|
|
36
|
+
set(path, value) {
|
|
37
|
+
if (typeof path === "string") {
|
|
38
|
+
const dotIndex = path.indexOf(".");
|
|
39
|
+
if (dotIndex !== -1) {
|
|
40
|
+
const key = path.slice(0, dotIndex);
|
|
41
|
+
const childPath = path.slice(dotIndex + 1);
|
|
42
|
+
if (this[key]) {
|
|
43
|
+
this[key].set(childPath, value);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
this[path] = value;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
for (const key in path) {
|
|
52
|
+
this.set(key, path[key]);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
watch(path, callback) {
|
|
58
|
+
const handles = [];
|
|
59
|
+
const pathArray = [];
|
|
60
|
+
if (typeof path === "object") {
|
|
61
|
+
pathArray.push(...path);
|
|
62
|
+
}
|
|
63
|
+
if (typeof path === "string") {
|
|
64
|
+
if (path.includes(",")) {
|
|
65
|
+
pathArray.push(...path.replace(" ", "").split(","));
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
pathArray.push(path);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
pathArray.forEach((item) => {
|
|
72
|
+
const dotIndex = item.indexOf(".");
|
|
73
|
+
const handle = dotIndex !== -1
|
|
74
|
+
? this[item.slice(0, dotIndex)].watch(item.slice(dotIndex + 1), callback)
|
|
75
|
+
: { path: item, callback };
|
|
76
|
+
handles.push(handle);
|
|
77
|
+
this._handles.add(handle);
|
|
78
|
+
});
|
|
79
|
+
const watchHandle = {
|
|
80
|
+
remove: () => {
|
|
81
|
+
handles.forEach((handle) => {
|
|
82
|
+
this._handles.delete(handle);
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
return watchHandle;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export default Accessor;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import Accessor from './accessor';
|
|
2
|
-
export default Accessor;
|
|
1
|
+
import Accessor from './accessor.js';
|
|
2
|
+
export default Accessor;
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import Accessor from './accessor.js';
|
|
2
|
-
export default Accessor;
|
|
1
|
+
import Accessor from './accessor.js';
|
|
2
|
+
export default Accessor;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geodaoyu/accessor",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"description": "mini @arcgis/core/core/Accessor & @arcgis/core/core/reactiveUtils",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
7
7
|
"scripts": {
|
|
@@ -11,11 +11,18 @@
|
|
|
11
11
|
"keywords": [
|
|
12
12
|
"Accessor",
|
|
13
13
|
"Esri",
|
|
14
|
-
"ArcGIS"
|
|
14
|
+
"ArcGIS",
|
|
15
|
+
"Proxy"
|
|
15
16
|
],
|
|
16
17
|
"author": "GeoDaoyu",
|
|
17
18
|
"license": "MIT",
|
|
18
19
|
"type": "module",
|
|
20
|
+
"files": [
|
|
21
|
+
"dist/**/*",
|
|
22
|
+
"src/**/*",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
19
26
|
"repository": {
|
|
20
27
|
"type": "git",
|
|
21
28
|
"url": "https://github.com/GeoDaoyu/Accessor.git"
|
package/src/accessor.ts
CHANGED
|
@@ -1,122 +1,119 @@
|
|
|
1
|
-
type WatchCallback = (
|
|
2
|
-
newValue: any,
|
|
3
|
-
oldValue: any,
|
|
4
|
-
propertyName: string,
|
|
5
|
-
target: Accessor
|
|
6
|
-
) => void;
|
|
7
|
-
|
|
8
|
-
interface WatchHandle extends Object {
|
|
9
|
-
/**
|
|
10
|
-
* Removes the watch handle.
|
|
11
|
-
*/
|
|
12
|
-
remove(): void;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface Handle {
|
|
16
|
-
path: string;
|
|
17
|
-
callback: Function;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
this[
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (typeof path === "
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export default observe(Accessor);
|
|
1
|
+
type WatchCallback = (
|
|
2
|
+
newValue: any,
|
|
3
|
+
oldValue: any,
|
|
4
|
+
propertyName: string,
|
|
5
|
+
target: Accessor
|
|
6
|
+
) => void;
|
|
7
|
+
|
|
8
|
+
interface WatchHandle extends Object {
|
|
9
|
+
/**
|
|
10
|
+
* Removes the watch handle.
|
|
11
|
+
*/
|
|
12
|
+
remove(): void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface Handle {
|
|
16
|
+
path: string;
|
|
17
|
+
callback: Function;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class Accessor {
|
|
21
|
+
declaredClass: string;
|
|
22
|
+
private _handles: Set<Handle>;
|
|
23
|
+
|
|
24
|
+
constructor(props: object = {}) {
|
|
25
|
+
// 为当前实例创建一个代理
|
|
26
|
+
const proxy = new Proxy(this, {
|
|
27
|
+
set: (target, key, value, receiver) => {
|
|
28
|
+
if (key !== '_handles' && target._handles) {
|
|
29
|
+
const oldValue = target[key];
|
|
30
|
+
target._handles.forEach((handle) => {
|
|
31
|
+
if (handle.path === key) {
|
|
32
|
+
handle.callback(value, oldValue, key, target);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return Reflect.set(target, key, value, receiver);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// 初始化属性
|
|
41
|
+
for (let prop in props) {
|
|
42
|
+
proxy[prop] = props[prop];
|
|
43
|
+
}
|
|
44
|
+
proxy.declaredClass = "Accessor";
|
|
45
|
+
proxy._handles = new Set();
|
|
46
|
+
|
|
47
|
+
return proxy;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get(path: string): any {
|
|
51
|
+
const dotIndex = path.indexOf(".");
|
|
52
|
+
if (dotIndex !== -1) {
|
|
53
|
+
const key = path.slice(0, dotIndex);
|
|
54
|
+
const value = path.slice(dotIndex + 1);
|
|
55
|
+
return this[key] && this[key].get(value);
|
|
56
|
+
}
|
|
57
|
+
return this[path];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
set(path: string | object, value: any): this {
|
|
61
|
+
if (typeof path === "string") {
|
|
62
|
+
const dotIndex = path.indexOf(".");
|
|
63
|
+
if (dotIndex !== -1) {
|
|
64
|
+
const key = path.slice(0, dotIndex);
|
|
65
|
+
const childPath = path.slice(dotIndex + 1);
|
|
66
|
+
if (this[key]) {
|
|
67
|
+
this[key].set(childPath, value);
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
this[path] = value;
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
for (const key in path) {
|
|
74
|
+
this.set(key, path[key]);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
watch(path: string | string[], callback: WatchCallback): WatchHandle {
|
|
82
|
+
const handles = [];
|
|
83
|
+
const pathArray = [];
|
|
84
|
+
if (typeof path === "object") {
|
|
85
|
+
pathArray.push(...path);
|
|
86
|
+
}
|
|
87
|
+
if (typeof path === "string") {
|
|
88
|
+
if (path.includes(",")) {
|
|
89
|
+
pathArray.push(...path.replace(" ", "").split(","));
|
|
90
|
+
} else {
|
|
91
|
+
pathArray.push(path);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
pathArray.forEach((item) => {
|
|
95
|
+
const dotIndex = item.indexOf(".");
|
|
96
|
+
const handle =
|
|
97
|
+
dotIndex !== -1
|
|
98
|
+
? this[item.slice(0, dotIndex)].watch(
|
|
99
|
+
item.slice(dotIndex + 1),
|
|
100
|
+
callback
|
|
101
|
+
)
|
|
102
|
+
: { path: item, callback };
|
|
103
|
+
|
|
104
|
+
handles.push(handle);
|
|
105
|
+
this._handles.add(handle);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const watchHandle = {
|
|
109
|
+
remove: () => {
|
|
110
|
+
handles.forEach((handle) => {
|
|
111
|
+
this._handles.delete(handle);
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
return watchHandle;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export default Accessor;
|
package/src/index.ts
CHANGED
package/test/construct.test.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import Accessor from '../dist/index.js';
|
|
2
|
-
import assert from 'assert';
|
|
3
|
-
|
|
4
|
-
describe('#constructor()', function() {
|
|
5
|
-
it('typeof accessor should be "object"', function() {
|
|
6
|
-
const accessor = new Accessor();
|
|
7
|
-
assert.strictEqual(typeof accessor, 'object');
|
|
8
|
-
});
|
|
9
|
-
/**
|
|
10
|
-
* 可以通过 对象的形式给类 赋初值
|
|
11
|
-
*/
|
|
12
|
-
it('accessor\'s props can be an object', function() {
|
|
13
|
-
const view = new Accessor({
|
|
14
|
-
zoom: 4,
|
|
15
|
-
});
|
|
16
|
-
assert.strictEqual(view.zoom, 4);
|
|
17
|
-
});
|
|
18
|
-
/**
|
|
19
|
-
* 子类可以继承Accessor
|
|
20
|
-
*/
|
|
21
|
-
it('subclass can extend from Accessor', function() {
|
|
22
|
-
class View extends Accessor {
|
|
23
|
-
constructor() {
|
|
24
|
-
super();
|
|
25
|
-
this.declaredClass = "View";
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
const view = new View();
|
|
29
|
-
assert.strictEqual(view instanceof Accessor, true);
|
|
30
|
-
});
|
|
31
|
-
});
|
package/test/get.test.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import Accessor from '../dist/index.js';
|
|
2
|
-
import assert from 'assert';
|
|
3
|
-
|
|
4
|
-
describe('#get()', function() {
|
|
5
|
-
/**
|
|
6
|
-
* 属性不存在,返回undefined
|
|
7
|
-
*/
|
|
8
|
-
it('should return undefined when the property in the path does not exist', function() {
|
|
9
|
-
const accessor = new Accessor();
|
|
10
|
-
assert.strictEqual(accessor.get('map'), undefined);
|
|
11
|
-
});
|
|
12
|
-
/**
|
|
13
|
-
* 设值取值
|
|
14
|
-
*/
|
|
15
|
-
it('should return 4 when the property is set to 4', function() {
|
|
16
|
-
const view = new Accessor();
|
|
17
|
-
view.set('zoom', 4);
|
|
18
|
-
assert.strictEqual(view.get('zoom'), 4);
|
|
19
|
-
});
|
|
20
|
-
it('deep path:should return undefined when the property in the path does not exist', function() {
|
|
21
|
-
const view = new Accessor();
|
|
22
|
-
assert.strictEqual(view.get('map.basemap'), undefined);
|
|
23
|
-
});
|
|
24
|
-
/**
|
|
25
|
-
* 获取属性的属性
|
|
26
|
-
*/
|
|
27
|
-
it('should return the property in the deep path', function() {
|
|
28
|
-
const map = new Accessor();
|
|
29
|
-
const basemap = new Accessor();
|
|
30
|
-
map.set('basemap', basemap);
|
|
31
|
-
basemap.set('title', 'World Topographic Map');
|
|
32
|
-
assert.strictEqual(map.get('basemap.title'), 'World Topographic Map');
|
|
33
|
-
});
|
|
34
|
-
});
|
package/test/set.test.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import Accessor from "../dist/index.js";
|
|
2
|
-
import assert from "assert";
|
|
3
|
-
|
|
4
|
-
describe("#set()", function () {
|
|
5
|
-
it("should return 4 when the property is set to 4", function () {
|
|
6
|
-
const view = new Accessor();
|
|
7
|
-
view.set("zoom", 4);
|
|
8
|
-
assert.strictEqual(view.get("zoom"), 4);
|
|
9
|
-
});
|
|
10
|
-
it("should return 4 when the property is 4", function () {
|
|
11
|
-
const view = new Accessor();
|
|
12
|
-
view.zoom = 4;
|
|
13
|
-
assert.strictEqual(view.zoom, 4);
|
|
14
|
-
});
|
|
15
|
-
/**
|
|
16
|
-
* 设置属性的属性
|
|
17
|
-
*/
|
|
18
|
-
it("deep path set property", function () {
|
|
19
|
-
const map = new Accessor();
|
|
20
|
-
const basemap = new Accessor();
|
|
21
|
-
map.set("basemap", basemap);
|
|
22
|
-
map.set("basemap.title", "World Topographic Map");
|
|
23
|
-
assert.strictEqual(map.get("basemap.title"), "World Topographic Map");
|
|
24
|
-
});
|
|
25
|
-
/**
|
|
26
|
-
* 设置属性的属性,当属性不存在的时候,不设置
|
|
27
|
-
*/
|
|
28
|
-
it("deep path set property which does not exist", function () {
|
|
29
|
-
const map = new Accessor();
|
|
30
|
-
map.set("basemap.title", "World Topographic Map");
|
|
31
|
-
assert.strictEqual(map.get("basemap.title"), undefined);
|
|
32
|
-
});
|
|
33
|
-
/**
|
|
34
|
-
* 可以通过对象的形式批量设置属性
|
|
35
|
-
*/
|
|
36
|
-
it("An object with key-value pairs can be passed into", function () {
|
|
37
|
-
const view = new Accessor();
|
|
38
|
-
view.set({
|
|
39
|
-
center: [-4.4861, 48.3904],
|
|
40
|
-
scale: 5000,
|
|
41
|
-
});
|
|
42
|
-
assert.strictEqual(view.get("scale"), 5000);
|
|
43
|
-
});
|
|
44
|
-
/**
|
|
45
|
-
* 柯里化
|
|
46
|
-
*/
|
|
47
|
-
it("An object with key-value pairs can be passed into", function () {
|
|
48
|
-
const view = new Accessor();
|
|
49
|
-
const updateView = view.set.bind(view);
|
|
50
|
-
updateView({
|
|
51
|
-
center: [-4.4861, 48.3904],
|
|
52
|
-
scale: 5000,
|
|
53
|
-
});
|
|
54
|
-
assert.strictEqual(view.get("scale"), 5000);
|
|
55
|
-
});
|
|
56
|
-
});
|
package/test/watch.test.js
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import Accessor from "../dist/index.js";
|
|
2
|
-
import assert from "assert";
|
|
3
|
-
class Counter extends Accessor {
|
|
4
|
-
constructor() {
|
|
5
|
-
super();
|
|
6
|
-
this.number = 0;
|
|
7
|
-
}
|
|
8
|
-
setNumber = (value) => {
|
|
9
|
-
this.number = value;
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
describe("#watch()", function () {
|
|
14
|
-
it("watch property change", function () {
|
|
15
|
-
const result = [];
|
|
16
|
-
const callback = (newValue, oldValue, propertyName, target) => {
|
|
17
|
-
result.push(newValue, oldValue, propertyName, target);
|
|
18
|
-
};
|
|
19
|
-
const view = new Accessor();
|
|
20
|
-
view.zoom = 4;
|
|
21
|
-
view.watch("zoom", callback);
|
|
22
|
-
view.zoom = 5;
|
|
23
|
-
assert.deepStrictEqual(result, [5, 4, "zoom", view]);
|
|
24
|
-
});
|
|
25
|
-
/**
|
|
26
|
-
* 深层属性的变更的监听
|
|
27
|
-
* 注意,此时callback的target是指向 拥有这个属性的类,而不是最外层的类
|
|
28
|
-
*/
|
|
29
|
-
it("watch deep path property change", function () {
|
|
30
|
-
const result = [];
|
|
31
|
-
const callback = (newValue, oldValue, propertyName, target) => {
|
|
32
|
-
result.push(newValue, oldValue, propertyName, target);
|
|
33
|
-
};
|
|
34
|
-
const view = new Accessor({
|
|
35
|
-
map: new Accessor({
|
|
36
|
-
basemap: new Accessor({
|
|
37
|
-
title: "streets-vector",
|
|
38
|
-
}),
|
|
39
|
-
}),
|
|
40
|
-
});
|
|
41
|
-
view.watch("map.basemap.title", callback);
|
|
42
|
-
view.map.basemap.title = "topo-vector";
|
|
43
|
-
assert.deepStrictEqual(result, [
|
|
44
|
-
"topo-vector",
|
|
45
|
-
"streets-vector",
|
|
46
|
-
"title",
|
|
47
|
-
view.map.basemap,
|
|
48
|
-
]);
|
|
49
|
-
});
|
|
50
|
-
/**
|
|
51
|
-
* 一个callback监听多个属性, 字符串形式
|
|
52
|
-
*/
|
|
53
|
-
it("watch multiple propertys change in string", function () {
|
|
54
|
-
const result = [];
|
|
55
|
-
const callback = (newValue, oldValue, propertyName, target) => {
|
|
56
|
-
result.push(newValue, oldValue, propertyName, target);
|
|
57
|
-
};
|
|
58
|
-
const view = new Accessor({
|
|
59
|
-
zoom: 12,
|
|
60
|
-
scale: 144447.638572,
|
|
61
|
-
});
|
|
62
|
-
view.watch("zoom, scale", callback);
|
|
63
|
-
view.zoom = 11;
|
|
64
|
-
view.scale = 288895.277144;
|
|
65
|
-
assert.deepStrictEqual(result, [
|
|
66
|
-
11,
|
|
67
|
-
12,
|
|
68
|
-
"zoom",
|
|
69
|
-
view,
|
|
70
|
-
288895.277144,
|
|
71
|
-
144447.638572,
|
|
72
|
-
"scale",
|
|
73
|
-
view,
|
|
74
|
-
]);
|
|
75
|
-
});
|
|
76
|
-
/**
|
|
77
|
-
* 一个callback监听多个属性, 数组形式
|
|
78
|
-
*/
|
|
79
|
-
it("watch multiple propertys change in string array", function () {
|
|
80
|
-
const result = [];
|
|
81
|
-
const callback = (newValue, oldValue, propertyName, target) => {
|
|
82
|
-
result.push(newValue, oldValue, propertyName, target);
|
|
83
|
-
};
|
|
84
|
-
const view = new Accessor({
|
|
85
|
-
zoom: 12,
|
|
86
|
-
scale: 144447.638572,
|
|
87
|
-
});
|
|
88
|
-
view.watch(["zoom", "scale"], callback);
|
|
89
|
-
view.zoom = 11;
|
|
90
|
-
view.scale = 288895.277144;
|
|
91
|
-
assert.deepStrictEqual(result, [
|
|
92
|
-
11,
|
|
93
|
-
12,
|
|
94
|
-
"zoom",
|
|
95
|
-
view,
|
|
96
|
-
288895.277144,
|
|
97
|
-
144447.638572,
|
|
98
|
-
"scale",
|
|
99
|
-
view,
|
|
100
|
-
]);
|
|
101
|
-
});
|
|
102
|
-
/**
|
|
103
|
-
* 调用remove方法移除handle,callback将不执行
|
|
104
|
-
*/
|
|
105
|
-
it("remove watch handle", function () {
|
|
106
|
-
const result = [];
|
|
107
|
-
const callback = (newValue, oldValue, propertyName, target) => {
|
|
108
|
-
result.push(newValue, oldValue, propertyName, target);
|
|
109
|
-
};
|
|
110
|
-
const view = new Accessor();
|
|
111
|
-
view.zoom = 4;
|
|
112
|
-
const handle = view.watch("zoom", callback);
|
|
113
|
-
handle.remove();
|
|
114
|
-
view.zoom = 5;
|
|
115
|
-
assert.deepStrictEqual(result, []);
|
|
116
|
-
});
|
|
117
|
-
/**
|
|
118
|
-
* 只在注册的属性变更后执行callback
|
|
119
|
-
*/
|
|
120
|
-
it("only watch registered property", function () {
|
|
121
|
-
const result = [];
|
|
122
|
-
const callback = (newValue, oldValue, propertyName, target) => {
|
|
123
|
-
result.push(newValue, oldValue, propertyName, target);
|
|
124
|
-
};
|
|
125
|
-
const view = new Accessor();
|
|
126
|
-
view.zoom = 4;
|
|
127
|
-
view.watch("scale", callback);
|
|
128
|
-
view.zoom = 5;
|
|
129
|
-
assert.deepStrictEqual(result, []);
|
|
130
|
-
});
|
|
131
|
-
/**
|
|
132
|
-
* 子类上的方法也可以被监听
|
|
133
|
-
*/
|
|
134
|
-
it("watch subclass member", function () {
|
|
135
|
-
const counter = new Counter();
|
|
136
|
-
const result = [];
|
|
137
|
-
const callback = (newValue, oldValue, propertyName, target) => {
|
|
138
|
-
result.push(newValue, oldValue, propertyName, target);
|
|
139
|
-
};
|
|
140
|
-
counter.number = 4;
|
|
141
|
-
counter.watch("number", callback);
|
|
142
|
-
counter.setNumber(5);
|
|
143
|
-
|
|
144
|
-
assert.deepStrictEqual(result, [5, 4, "number", counter]);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* 子类上的方法 监听变更次数
|
|
149
|
-
*/
|
|
150
|
-
it("watch subclass member changed times", function () {
|
|
151
|
-
const counter = new Counter();
|
|
152
|
-
let times = 0;
|
|
153
|
-
const callback = () => {
|
|
154
|
-
times++;
|
|
155
|
-
};
|
|
156
|
-
counter.watch("number", callback);
|
|
157
|
-
counter.number = 1; // +1;
|
|
158
|
-
counter.number = 1; // +1;
|
|
159
|
-
counter.set("number", 2); // +1;
|
|
160
|
-
counter.set("number", 2); // +1;
|
|
161
|
-
counter.set({ number: 3 }); // +1;
|
|
162
|
-
counter.set({ number: 3 }); // +1;
|
|
163
|
-
counter.setNumber(4); // +1;
|
|
164
|
-
counter.setNumber(4); // +1;
|
|
165
|
-
|
|
166
|
-
assert.equal(times, 8);
|
|
167
|
-
});
|
|
168
|
-
});
|
package/tsconfig.json
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"experimentalDecorators": true,
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"target": "ESNext",
|
|
6
|
-
"sourceMap": false,
|
|
7
|
-
"rootDir": "./src",
|
|
8
|
-
"outDir": "./dist",
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"declaration": true,
|
|
11
|
-
"skipLibCheck": true,
|
|
12
|
-
"moduleResolution": "node",
|
|
13
|
-
},
|
|
14
|
-
"include": [
|
|
15
|
-
"src/**/*.ts",
|
|
16
|
-
],
|
|
17
|
-
"exclude": []
|
|
18
|
-
}
|