ms-vite-plugin 1.4.41 → 1.4.43

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/docs/api/node.md CHANGED
@@ -1,439 +1,328 @@
1
1
  # 节点模块 (Node)
2
2
 
3
- 节点模块提供了强大的 UI 元素访问和操作功能,可以通过各种条件选择和操作界面元素。
3
+ 用于查找和操作当前界面上的控件节点。
4
4
 
5
- **注意事项**
5
+ **注意**
6
6
 
7
- - 此模块仅支持 快点 Agent 模式使用
8
- - 节点用完需要调用 `releaseNode` 方法释放内存,找完节点就能释放,不需要点击后释放
7
+ - 仅支持快点 Agent 模式
8
+ - 用完调用 `releaseNode()` 释放;找完节点即可释放,不必等点击结束
9
9
 
10
- ## 节点选择器 (NodeSelector)
10
+ **基本流程**
11
11
 
12
- 节点选择器是访问 UI 元素的核心工具,提供了灵活的筛选和查找机制。
13
-
14
- ### 创建节点选择器
12
+ ```text
13
+ createNodeSelector → 设置筛选条件 → getOneNodeInfo / getNodeInfo
14
+ 点击 / 输入 / 设值等 → releaseNode
15
+ ```
15
16
 
16
- #### createNodeSelector - 创建节点选择器
17
+ ---
17
18
 
18
- 创建一个新的节点选择器实例。
19
+ ## 创建选择器
19
20
 
20
21
  ```typescript
21
22
  function createNodeSelector(params?: {
22
- maxDepth?: number; // 最大层级深度,默认 50
23
- mode?: number; // 抓取模式:模式 1、模式 2、模式 3,默认模式 1
23
+ maxDepth?: number; // 最大层级,默认 50;越小通常越快
24
+ mode?: number; // 抓取模式 1 | 2 | 3,默认 1
24
25
  }): NodeSelector;
25
26
  ```
26
27
 
27
- **参数说明:**
28
-
29
- | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
30
- | ---------- | ------ | -------- | ------ | --------------------------- |
31
- | `maxDepth` | number | 否 | 50 | 遍历的最大层级深度,默认 50 |
32
- | `mode` | number | 否 | 1 | 抓取模式。支持模式 1、模式 2、模式 3,默认模式 1 |
33
-
34
- **返回值:**
35
-
36
- | 类型 | 描述 |
37
- | -------------- | ---------------------- |
38
- | `NodeSelector` | 新创建的节点选择器实例 |
39
-
40
- **示例:**
41
-
42
- ```typescript
43
- // 创建选择器
44
- const selector = createNodeSelector({
45
- maxDepth: 20, // 最大20层深度
46
- mode: 1, // 默认模式 1
47
- });
48
- ```
49
-
50
- ### 节点信息接口
51
-
52
- #### NodeBoundsInfo - 节点边界信息。
53
-
54
- ```typescript
55
- interface NodeBoundsInfo {
56
- x: number; // x坐标
57
- y: number; // y坐标
58
- width: number; // 宽度
59
- height: number; // 高度
60
- centerX: number; // 中心点x坐标
61
- centerY: number; // 中心点y坐标
62
- }
63
- ```
64
-
65
- #### NodeInfo - 节点详细信息。
66
-
67
- ```typescript
68
- interface NodeInfo {
69
- id: string; // 节点ID
70
- identifier: string; // 节点标识符
71
- label: string; // 节点标签
72
- type: string; // 节点类型
73
- value: string; // 节点值
74
- placeholderValue: string; // 节点占位符值
75
- title: string; // 节点名称
76
- enabled: boolean; // 是否启用
77
- bounds: NodeBoundsInfo; // 边界信息
78
- depth: number; // 层级深度
79
- index: number; // 索引
80
- parentId: string; // 父节点ID
81
- childCount: number; // 子节点数量
82
-
83
- // 操作方法
84
- clickCenter(): boolean; // 点击中心
85
- clickRandom(): boolean; // 随机点击
86
- hittable(): boolean; // 节点是否可接收事件,用于判断节点是否在屏幕可见
87
- tap(): boolean; // 无障碍点击
88
- doubleTap(): boolean; // 无障碍双击
89
- press(duration: number): boolean; // 无障碍长按,duration 单位毫秒
90
- scrollToVisible(): boolean; // 将节点滚动到可见区域
91
- clearInput(): boolean; // 清空输入
92
- input(text: string): boolean; // 追加输入(聚焦后输入)
93
- setValue(text: string): boolean; // 设置节点的值(见下方支持控件)
94
- parent(): NodeInfo | null; // 获取父节点
95
- child(index: number): NodeInfo | null; // 获取子节点
96
- allChildren(): NodeInfo[]; // 获取所有子节点
97
- siblings(): NodeInfo[]; // 获取兄弟节点
98
- previousSiblings(): NodeInfo[]; // 获取前面的兄弟节点
99
- nextSiblings(): NodeInfo[]; // 获取后面的兄弟节点
100
- }
101
- ```
102
-
103
- ### 选择器方法
104
-
105
- #### 获取节点
28
+ | 参数 | 默认 | 说明 |
29
+ | --- | --- | --- |
30
+ | `maxDepth` | `50` | 抓取深度,深层控件抓不到时可调大 |
31
+ | `mode` | `1` | 抓取模式,可选 `1` / `2` / `3`,默认 `1` |
106
32
 
107
33
  ```typescript
108
- // releaseNode - 释放内存
109
- releaseNode(): void;
110
-
111
- // xml - 获取当前页面的 XML 字符串
112
- xml(timeout?: number): string | null;
113
-
114
- // 获取多个节点
115
- getNodeInfo(timeout?: number): NodeInfo[]
116
-
117
- // 获取单个节点
118
- getOneNodeInfo(timeout?: number): NodeInfo | null
119
-
120
- // 加载节点数据
121
- loadNode(timeout?: number): NodeSelector;
122
-
123
- // 清除所有选择条件
124
- clearSelector(): NodeSelector;
34
+ const selector = createNodeSelector();
35
+ const shallow = createNodeSelector({ maxDepth: 15 });
36
+ const listPage = createNodeSelector({ mode: 2 });
125
37
  ```
126
38
 
127
- **示例:**
39
+ ---
40
+
41
+ ## 节点信息
42
+
43
+ ### 位置 `NodeBoundsInfo`
44
+
45
+ | 字段 | 说明 |
46
+ | --- | --- |
47
+ | `x` / `y` | 左上角 |
48
+ | `width` / `height` | 宽高 |
49
+ | `centerX` / `centerY` | 中心点 |
50
+
51
+ ### 节点 `NodeInfo`
52
+
53
+ **属性**
54
+
55
+ | 字段 | 说明 |
56
+ | --- | --- |
57
+ | `id` | 节点 ID(内部定位用,不要改) |
58
+ | `identifier` | 控件标识符 |
59
+ | `label` | 标签文案 |
60
+ | `type` | 类型,如 `XCUIElementTypeButton` |
61
+ | `value` | 当前值 |
62
+ | `placeholderValue` | 输入框占位文字 |
63
+ | `title` | 标题 |
64
+ | `enabled` | 是否启用 |
65
+ | `bounds` | 位置大小 |
66
+ | `depth` | 层级 |
67
+ | `index` | 在父节点下的序号 |
68
+ | `parentId` | 父节点 ID |
69
+ | `childCount` | 子节点数量 |
70
+
71
+ **方法**
72
+
73
+ | 方法 | 说明 |
74
+ | --- | --- |
75
+ | `hittable()` | 当前是否可点击(可见且未被挡住) |
76
+ | `scrollToVisible()` | 滚动到可见区域 |
77
+ | `tap()` | 单击(不可见时会先尝试滚到可见) |
78
+ | `doubleTap()` | 双击 |
79
+ | `press(duration?)` | 长按,`duration` 单位毫秒,默认 500 |
80
+ | `clickCenter()` | 点击中心坐标 |
81
+ | `clickRandom()` | 在节点范围内随机点击 |
82
+ | `clearInput()` | 清空输入内容 |
83
+ | `input(text)` | 追加输入(不先清空) |
84
+ | `setValue(text)` | 设置值(见下方) |
85
+ | `parent()` | 父节点 |
86
+ | `child(index)` | 第 `index` 个子节点 |
87
+ | `allChildren()` | 全部子节点 |
88
+ | `siblings()` | 全部兄弟节点 |
89
+ | `previousSiblings()` | 前面的兄弟 |
90
+ | `nextSiblings()` | 后面的兄弟 |
91
+
92
+ ---
93
+
94
+ ## 选择器方法
95
+
96
+ ### 加载与结果
97
+
98
+ | 方法 | 说明 |
99
+ | --- | --- |
100
+ | `releaseNode()` | 释放内存 |
101
+ | `loadNode(timeout?)` | 重新加载界面节点,默认超时 5000ms |
102
+ | `clearSelector()` | 清除已设置的筛选条件 |
103
+ | `xml(timeout?)` | 获取界面 XML,失败返回 `null` |
104
+ | `getNodeInfo(timeout?)` | 获取所有匹配节点 |
105
+ | `getOneNodeInfo(timeout?)` | 获取第一个匹配节点,没有则 `null` |
106
+
107
+ `timeout` 单位均为毫秒,默认 `5000`。
128
108
 
129
109
  ```typescript
130
110
  const selector = createNodeSelector();
131
-
132
- // 获取所有匹配的节点
133
- const allNodes = selector.getNodeInfo(5000);
134
- logi(`找到 ${allNodes.length} 个节点`);
135
-
136
- // 获取第一个匹配的节点
137
- const firstNode = selector.getOneNodeInfo(3000);
138
- if (firstNode) {
139
- logi(`节点标签: ${firstNode.label}`);
140
- }
141
-
111
+ const nodes = selector.label("确定").getNodeInfo(5000);
112
+ const one = selector.getOneNodeInfo(3000);
113
+ const xml = selector.xml();
142
114
  selector.releaseNode();
143
115
  ```
144
116
 
145
- #### 条件筛选
146
-
147
- ##### 文本相关
117
+ ### 筛选条件
148
118
 
149
- ```typescript
150
- // 精确匹配标签
151
- label(label: string): NodeSelector
152
-
153
- // 标签模糊匹配
154
- labelMatch(match: string): NodeSelector
119
+ 可链式调用,多个条件同时满足(并且关系)。
120
+ `Match` 的为模糊/正则匹配。
155
121
 
156
- // 精确匹配名称
157
- title(title: string): NodeSelector
122
+ **文本**
158
123
 
159
- // 名称模糊匹配
160
- titleMatch(match: string): NodeSelector
124
+ | 方法 | 说明 |
125
+ | --- | --- |
126
+ | `label` / `labelMatch` | 标签 |
127
+ | `title` / `titleMatch` | 标题 |
128
+ | `identifier` / `identifierMatch` | 标识符 |
129
+ | `value` / `valueMatch` | 值 |
130
+ | `placeholderValue` / `placeholderValueMatch` | 占位文字 |
161
131
 
162
- // 精确匹配标识符
163
- identifier(identifier: string): NodeSelector
132
+ **类型与状态**
164
133
 
165
- // 标识符模糊匹配
166
- identifierMatch(match: string): NodeSelector
134
+ | 方法 | 说明 |
135
+ | --- | --- |
136
+ | `type` / `typeMatch` | 类型,如 `XCUIElementTypeButton` |
137
+ | `enabled` | 是否启用 |
167
138
 
168
- // 精确匹配值
169
- value(value: string): NodeSelector
139
+ **位置与结构**
170
140
 
171
- // 值模糊匹配
172
- valueMatch(match: string): NodeSelector
173
- ```
174
-
175
- **示例:**
141
+ | 方法 | 说明 |
142
+ | --- | --- |
143
+ | `index` | 序号 |
144
+ | `depth` | 层级 |
145
+ | `childCount` | 子节点数,支持数字或如 `">0"` |
146
+ | `bounds(x, y, width, height)` | 区域 |
147
+ | `xpath` | XPath |
148
+ | `id` | 按节点 ID |
176
149
 
177
150
  ```typescript
178
- // 查找标签为"确定"的按钮
179
- const confirmButton = selector.label("确定").getOneNodeInfo(3000);
180
-
181
- // 查找包含"登录"的元素
182
- const loginElements = selector.labelMatch(".*登录.*").getNodeInfo(3000);
151
+ // 精确
152
+ selector.label("确定").type("XCUIElementTypeButton").getOneNodeInfo(3000);
183
153
 
184
- // 查找名称包含"button"的元素
185
- const buttons = selector.titleMatch("button").getNodeInfo(3000);
154
+ // 模糊
155
+ selector.labelMatch(".*登录.*").getNodeInfo(3000);
156
+ selector.identifierMatch("^login_").getNodeInfo(3000);
186
157
 
187
- // 查找值为"submit"的元素
188
- const submitElement = selector.value("submit").getOneNodeInfo(2000);
189
-
190
- // 通过标识符查找
191
- const elById = selector.identifier("login_btn").getOneNodeInfo(2000);
192
- const fuzzy = selector.identifierMatch("^login_.*").getNodeInfo(3000);
158
+ // 组合
159
+ selector
160
+ .type("XCUIElementTypeTextField")
161
+ .enabled(true)
162
+ .getOneNodeInfo(3000);
193
163
  ```
194
164
 
195
- ##### 类型和属性
165
+ 常见类型:`XCUIElementTypeButton`、`StaticText`、`TextField`、`SecureTextField`、`TextView`、`SearchField`、`Cell`、`Table`、`CollectionView`、`PickerWheel`、`Switch`、`Slider` 等。
196
166
 
197
- ```typescript
198
- // 精确匹配类型
199
- type(type: string): NodeSelector
167
+ ---
200
168
 
201
- // 类型模糊匹配
202
- typeMatch(match: string): NodeSelector
169
+ ## 节点操作说明
203
170
 
204
- // 启用状态
205
- enabled(enabled: boolean): NodeSelector
206
- ```
207
-
208
- **示例:**
171
+ ### 是否可点 / 滚到可见
209
172
 
210
173
  ```typescript
211
- const selector = createNodeSelector();
212
- // 查找所有按钮
213
- const allButtons = selector.type("XCUIElementTypeButton").getNodeInfo(3000);
214
-
215
- // 查找所有文本框
216
- const textFields = selector
217
- .typeMatch("XCUIElementTypeTextField")
218
- .getNodeInfo(3000);
219
-
220
- // 查找启用的元素
221
- const enabledElements = selector.enabled(true).getNodeInfo(3000);
222
-
223
- selector.releaseNode();
174
+ if (node.hittable()) {
175
+ node.tap();
176
+ } else {
177
+ node.scrollToVisible();
178
+ node.tap();
179
+ }
224
180
  ```
225
181
 
226
- ##### 位置和结构
182
+ - `hittable()`:当前能否点到
183
+ - `scrollToVisible()`:手动滚到可见
184
+ - `tap` / `doubleTap` / `press`:不可见时会自动尝试滚到可见再操作
227
185
 
228
- ```typescript
229
- // 索引位置
230
- index(index: number): NodeSelector
231
-
232
- // 层级深度
233
- depth(depth: number): NodeSelector
186
+ ### 点击
234
187
 
235
- // 子节点数量
236
- childCount(childCount: number | string): NodeSelector
188
+ | 方法 | 说明 |
189
+ | --- | --- |
190
+ | `tap()` | 推荐,单击 |
191
+ | `doubleTap()` | 双击 |
192
+ | `press(ms?)` | 长按,默认 500ms |
193
+ | `clickCenter()` | 点中心坐标 |
194
+ | `clickRandom()` | 范围内随机点 |
237
195
 
238
- // 边界范围
239
- bounds(x: number, y: number, width: number, height: number): NodeSelector
196
+ ```typescript
197
+ const btn = selector
198
+ .label("确定")
199
+ .type("XCUIElementTypeButton")
200
+ .getOneNodeInfo(3000);
240
201
 
241
- // XPath 路径
242
- xpath(path: string): NodeSelector
202
+ if (btn) {
203
+ btn.tap();
204
+ btn.doubleTap();
205
+ btn.press(800);
206
+ }
243
207
  ```
244
208
 
245
- **示例:**
246
-
247
- ```typescript
248
- const selector = createNodeSelector();
249
-
250
- // 查找第一个元素
251
- const firstElement = selector.index(0).getOneNodeInfo(2000);
209
+ ### 输入与设值
252
210
 
253
- // 查找特定深度的元素
254
- const level3Elements = selector.depth(3).getNodeInfo(3000);
211
+ | 方法 | 说明 |
212
+ | --- | --- |
213
+ | `clearInput()` | 清空 |
214
+ | `input(text)` | 追加输入,不清空原内容 |
215
+ | `setValue(text)` | 按控件类型设置 |
255
216
 
256
- // 查找有子节点的元素
257
- const parentElements = selector.childCount(">0").getNodeInfo(3000);
217
+ **`setValue` 行为**
258
218
 
259
- // 查找特定区域的元素
260
- const regionElements = selector.bounds(100, 100, 200, 50).getNodeInfo(3000);
219
+ | 控件类型 | 传参 | 效果 |
220
+ | --- | --- | --- |
221
+ | `PickerWheel` | 选项文案,如 `"1小时"` | 滚到该选项 |
222
+ | 文本框类(TextField 等) | 字符串 | 聚焦后追加输入,不先清空 |
261
223
 
262
- // 使用 XPath 查找
263
- const xpathElements = selector.xpath("//*[@title='快点JS']").getNodeInfo(3000);
224
+ 覆盖原内容请先清空:
264
225
 
265
- selector.releaseNode();
226
+ ```typescript
227
+ field.clearInput();
228
+ field.setValue("hello");
229
+ // 或
230
+ field.clearInput();
231
+ field.input("hello");
266
232
  ```
267
233
 
268
- ### 节点操作
269
-
270
- #### 点击操作
271
-
272
234
  ```typescript
273
- // 点击节点中心(坐标点击)
274
- node.clickCenter(): boolean;
275
-
276
- // 随机点击节点区域(坐标点击)
277
- node.clickRandom(): boolean;
278
-
279
- // 节点是否可接收事件(用于判断是否显示在屏幕上)
280
- node.hittable(): boolean;
281
-
282
- // 无障碍点击
283
- node.tap(): boolean;
284
-
285
- // 无障碍双击
286
- node.doubleTap(): boolean;
287
-
288
- // 无障碍长按,duration 单位毫秒
289
- node.press(duration: number): boolean;
290
-
291
- // 将节点滚动到可见区域
292
- node.scrollToVisible(): boolean;
293
-
294
- // 清空输入
295
- node.clearInput(): boolean;
296
-
297
- // 追加输入
298
- node.input(text: string): boolean;
299
-
300
- // 设置节点的值
301
- node.setValue(text: string): boolean;
235
+ const wheel = selector.type("XCUIElementTypePickerWheel").getOneNodeInfo(3000);
236
+ if (wheel) {
237
+ wheel.setValue("1小时");
238
+ }
302
239
  ```
303
240
 
304
- #### tap / doubleTap / press - 无障碍手势
305
-
306
- 通过无障碍 API 直接操作节点,不依赖坐标点击。
307
-
308
- | 方法 | 参数 | 说明 |
309
- | --- | --- | --- |
310
- | `tap()` | 无 | 无障碍单击 |
311
- | `doubleTap()` | 无 | 无障碍双击 |
312
- | `press(duration)` | `duration`:长按持续时间,单位毫秒 | 无障碍长按 |
313
-
314
- **示例:**
241
+ ### 树导航
315
242
 
316
243
  ```typescript
317
- const selector = createNodeSelector();
318
-
319
- const btn = selector.label("确定").type("XCUIElementTypeButton").getOneNodeInfo(3000);
320
- if (btn) {
321
- // 无障碍单击
322
- btn.tap();
323
-
324
- // 无障碍双击
325
- btn.doubleTap();
326
-
327
- // 无障碍长按 800ms
328
- btn.press(800);
244
+ const field = selector.type("XCUIElementTypeTextField").getOneNodeInfo(3000);
245
+ if (field) {
246
+ const parent = field.parent();
247
+ const children = parent?.allChildren() ?? [];
248
+ const prev = field.previousSiblings();
249
+ const next = field.nextSiblings();
250
+ const second = parent?.child(1);
329
251
  }
330
-
331
- selector.releaseNode();
332
252
  ```
333
253
 
334
- #### setValue - 设置节点的值
254
+ ---
335
255
 
336
- 按控件类型自动处理,常用支持如下:
337
-
338
- | 控件类型 | 传参示例 | 说明 |
339
- | --- | --- | --- |
340
- | `XCUIElementTypePickerWheel` | `"1小时"` | 滚轮选到对应选项文案 |
341
- | `XCUIElementTypeTextField` | `"hello"` | 先聚焦再输入文本 |
342
- | `XCUIElementTypeSecureTextField` | `"123456"` | 同上 |
343
- | `XCUIElementTypeTextView` | `"多行内容"` | 同上 |
344
- | `XCUIElementTypeSearchField` | `"关键词"` | 同上 |
256
+ ## 示例
345
257
 
346
- 文本类控件不会先清空已有内容;需要清空时先调用 `clearInput()`。
347
-
348
- **示例:**
258
+ ### 登录
349
259
 
350
260
  ```typescript
351
261
  const selector = createNodeSelector();
352
262
 
353
- // 查找并点击确定按钮
354
- const confirmBtn = selector
355
- .label("确定")
356
- .type("XCUIElementTypeButton")
357
- .getOneNodeInfo(3000);
263
+ try {
264
+ const user = selector.type("XCUIElementTypeTextField").getOneNodeInfo(5000);
265
+ if (user) {
266
+ user.clearInput();
267
+ user.setValue("demo_user");
268
+ }
358
269
 
359
- if (confirmBtn) {
360
- const isHittable = confirmBtn.hittable();
361
- logi(`是否可接收事件: ${isHittable}`);
270
+ const pass = selector
271
+ .clearSelector()
272
+ .type("XCUIElementTypeSecureTextField")
273
+ .getOneNodeInfo(3000);
274
+ if (pass) {
275
+ pass.clearInput();
276
+ pass.setValue("password");
277
+ }
362
278
 
363
- confirmBtn.scrollToVisible();
364
- // 优先使用无障碍点击;也可用 clickCenter / clickRandom 做坐标点击
365
- const clicked = confirmBtn.tap();
366
- if (clicked) {
367
- logi("成功点击确定按钮");
279
+ const login = selector
280
+ .clearSelector()
281
+ .labelMatch(".*登录.*")
282
+ .type("XCUIElementTypeButton")
283
+ .getOneNodeInfo(3000);
284
+ if (login) {
285
+ login.tap();
368
286
  }
287
+ } finally {
288
+ selector.releaseNode();
369
289
  }
290
+ ```
370
291
 
371
- // 文本框:可先清空再设值,或直接追加输入
372
- const field = selector.type("XCUIElementTypeTextField").getOneNodeInfo(3000);
373
- if (field) {
374
- field.clearInput();
375
- field.setValue("hello");
376
- }
292
+ ### 列表里靠后的项
377
293
 
378
- // 滚轮:传界面上的选项文案
379
- const wheel = selector.type("XCUIElementTypePickerWheel").getOneNodeInfo(3000);
380
- if (wheel) {
381
- wheel.setValue("1小时");
294
+ ```typescript
295
+ const selector = createNodeSelector({ mode: 2 });
296
+ const item = selector.label("第 30 项").getOneNodeInfo(5000);
297
+ if (item) {
298
+ item.tap(); // 不在可见区域时会自动滚动
382
299
  }
383
-
384
- // 随机点击避免检测
385
- const randomClick = confirmBtn?.clickRandom();
386
-
387
300
  selector.releaseNode();
388
301
  ```
389
302
 
390
- #### 节点导航
303
+ ### 查看界面结构
391
304
 
392
305
  ```typescript
393
- // 获取父节点
394
- node.parent(): NodeInfo | null
395
-
396
- // 获取指定索引的子节点
397
- node.child(index: number): NodeInfo | null
398
-
399
- // 获取所有子节点
400
- node.allChildren(): NodeInfo[]
401
-
402
- // 获取兄弟节点
403
- node.siblings(): NodeInfo[]
404
-
405
- // 获取前面的兄弟节点
406
- node.previousSiblings(): NodeInfo[]
407
-
408
- // 获取后面的兄弟节点
409
- node.nextSiblings(): NodeInfo[]
306
+ const selector = createNodeSelector();
307
+ const xml = selector.xml(8000);
308
+ if (xml) {
309
+ logi(xml);
310
+ }
311
+ selector.releaseNode();
410
312
  ```
411
313
 
412
- **示例:**
413
-
414
- ```typescript
415
- const selector = createNodeSelector();
314
+ ---
416
315
 
417
- // 查找输入框并获取其父容器
418
- const textField = selector
419
- .type("XCUIElementTypeTextField")
420
- .getOneNodeInfo(3000);
316
+ ## 常见问题
421
317
 
422
- if (textField) {
423
- const container = textField.parent();
424
- if (container) {
425
- logi(`容器类型: ${container.type}`);
318
+ **找不到节点**
319
+ 加大超时;减少条件或改用 `*Match`;换 `mode`;用 `xml()` 看实际文案和类型。
426
320
 
427
- // 获取容器的所有子元素
428
- const siblings = container.allChildren();
429
- logi(`容器包含 ${siblings.length} 个子元素`);
321
+ **点了没反应**
322
+ 先看 `hittable()`;确认点到的是目标控件;可对比 `clickCenter()`。
430
323
 
431
- // 查找同级的按钮
432
- const siblingButtons = siblings.filter(
433
- (node) => node.type === "XCUIElementTypeButton",
434
- );
435
- }
436
- }
324
+ **输入叠在旧文字后面**
325
+ `input` / 文本类 `setValue` 是追加,先 `clearInput()`。
437
326
 
438
- selector.releaseNode();
439
- ```
327
+ **滚轮设不中**
328
+ `setValue` 要传界面上显示的选项文案;确认类型是 `PickerWheel`;多列时选对那一列。