Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .agents/skills/mpx2rn/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ Mpx 是一个以微信小程序语法为基础、进行了类 Vue 语法拓展

1. **生命周期 / 构造选项**:仅使用 [逻辑能力参考](./references/rn-script-reference.md) 中标注 RN 支持的生命周期与构造选项;避免使用 `onShareTimeline` / `onTabItemTap` / `onAddToFavorites` / `onSaveExitState` 等 RN 不支持项。
2. **环境 API**:通过 `@mpxjs/api-proxy` 提供的统一 `mpx.xxx` API 调用环境能力,避免直接使用 `wx.xxx` / `my.xxx`;具体支持范围见 [环境 API 参考](./references/rn-api-reference.md);如用户通过 `custom` 配置扩充拓展了环境 API 能力,以用户说明为准。
3. **selector 映射**:脚本中的 `selectComponent` / `selectAllComponents` / `createSelectorQuery` / `createIntersectionObserver` 等 selector API 仅支持 `#id` / `.class`,且对应模板节点须声明空 `wx:ref` 以建立编译期 selector 映射。详见 [逻辑能力参考 · 实例方法与属性](./references/rn-script-reference.md#页面--组件实例方法与属性)。
3. **selector 映射**:脚本中的 `selectComponent` / `selectAllComponents` / `createSelectorQuery` / `createIntersectionObserver` 等 selector API 仅支持 `#id` / `.class`,且对应模板节点或组件须声明空 `wx:ref` 以建立编译期 selector 映射。详见 [逻辑能力参考 · 实例方法与属性](./references/rn-script-reference.md#页面--组件实例方法与属性)。


### 样式(style)约束
Expand Down Expand Up @@ -130,14 +130,14 @@ Mpx 是一个以微信小程序语法为基础、进行了类 Vue 语法拓展

- 读取 [模板能力参考](./references/rn-template-reference.md),对 `<template>` 中使用的基础组件及其属性与事件逐一核对 RN 支持情况。
- 检查动态 `class` / `style` 是否使用了 `{{}}` 拼接字符串,统一改造为 `wx:class` / `wx:style` 指令绑定。
- 检查 `<script>` 中 selector 类 API 引用的节点是否声明空 `wx:ref`,未声明的须补齐。
- 检查 `<script>` 中 selector 类 API 引用的节点或组件是否声明空 `wx:ref`,未声明的须补齐。
- 对于无法等效实现的部分使用 [模板条件编译](./references/conditional-compile.md#模板条件编译)(`@mode` / `@_mode` / `mpxTagName@mode`)进行平台隔离,并添加 `todo` 注释记录差异原因。

#### 2. 脚本(script)适配改造

- 读取 [逻辑能力参考](./references/rn-script-reference.md) 与 [环境 API 参考](./references/rn-api-reference.md),对 `<script>` 中的生命周期、构造选项、实例方法与环境 API 调用逐一核对 RN 支持情况。
- 平台直连 API(如 `wx.xxx` / `my.xxx`)统一替换为 `mpx.xxx` 接入 `@mpxjs/api-proxy` 抹平的实现。
- 涉及 selector 的脚本逻辑须改造为 `#id` / `.class` 写法,并在对应模板节点添加空 `wx:ref`。
- 涉及 selector 的脚本逻辑须改造为 `#id` / `.class` 写法,并在对应模板节点或组件添加空 `wx:ref`。
- 对于 RN 平台不支持的脚本逻辑分支,使用 [脚本条件编译](./references/conditional-compile.md#脚本条件编译) 进行平台隔离,并添加 `todo` 注释记录差异原因。

#### 3. 样式(style)适配改造
Expand Down Expand Up @@ -187,7 +187,7 @@ Mpx 是一个以微信小程序语法为基础、进行了类 Vue 语法拓展
**模板(template)**
- [ ] `<template>` 中使用的基础组件、属性、事件均在 [模板能力参考](./references/rn-template-reference.md) 标注为 RN 支持,或已通过模板条件编译进行平台隔离;如用户通过 `rnConfig.customBuiltInComponents` 编译配置扩充拓展了基础组件能力,以用户说明为准。
- [ ] 动态 `class` / `style` 已改造为 `wx:class` / `wx:style` 指令,未在属性值内使用 `{{}}` 拼接。
- [ ] selector 类 API 引用的模板节点均已声明空 `wx:ref` 完成编译期映射。
- [ ] selector 类 API 引用的模板节点或组件均已声明空 `wx:ref` 完成编译期映射。

**脚本(script)**
- [ ] `<script>` 中使用的生命周期、构造选项、实例方法与环境 API 均在 [逻辑能力参考](./references/rn-script-reference.md) 与 [环境 API 参考](./references/rn-api-reference.md) 标注为 RN 支持,或已通过脚本条件编译进行平台隔离;如用户通过 `custom` 配置扩充拓展了环境 API 能力,以用户说明为准。
Expand Down Expand Up @@ -232,7 +232,7 @@ Mpx 是一个以微信小程序语法为基础、进行了类 Vue 语法拓展

按 SFC 四个区块依次实现,全程遵循 [通用约束与适配原则](#通用约束与适配原则):

- **`<template>`**:读取 [模板能力参考](./references/rn-template-reference.md),仅选用 RN 支持的基础组件、属性与事件;动态样式类名绑定使用 `wx:class` / `wx:style`;selector 类 API 涉及节点声明空 `wx:ref`。
- **`<template>`**:读取 [模板能力参考](./references/rn-template-reference.md),仅选用 RN 支持的基础组件、属性与事件;动态样式类名绑定使用 `wx:class` / `wx:style`;selector 类 API 涉及节点或组件声明空 `wx:ref`。
- **`<script>`**:读取 [逻辑能力参考](./references/rn-script-reference.md) 与 [环境 API 参考](./references/rn-api-reference.md),仅使用 RN 支持的生命周期、构造选项与 API;统一通过 `mpx.xxx` 调用环境能力。
- **优先使用组合式 API**:新建组件优先使用 `<script setup>` 风格的组合式 API 编写逻辑,生命周期须在 `<script setup>` 顶层同步注册,详见 [逻辑能力参考 · 组合式 API](./references/rn-script-reference.md#组合式-api)。
- **状态管理优先使用 `@mpxjs/pinia`**:新项目、新状态域或与组合式 API 协同时,使用 `@mpxjs/pinia`(Pinia 风格);仅当工程已深度使用 `@mpxjs/store`(Vuex 风格)时继续维护沿用,避免同一业务域两套方案并存。详见 [逻辑能力参考 · 状态管理](./references/rn-script-reference.md#状态管理)。
Expand Down
2 changes: 2 additions & 0 deletions .agents/skills/mpx2rn/references/rn-api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1572,6 +1572,8 @@ mpx.config.rnConfig.wifiPermission = () => {

工厂方法:创建 **`SelectorQuery`**(非 `success` / `fail` 入参模型)。

RN 中 `select` 支持查询声明了空 `wx:ref` 的基础节点和自定义组件;查询自定义组件时,默认测量非 virtualHost 场景下的 host 根节点。

#### 入参

无;若需组件作用域,与小程序一致传入 **组件实例**(以实现为准)。
Expand Down
14 changes: 7 additions & 7 deletions .agents/skills/mpx2rn/references/rn-script-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,9 @@
| `getPageId()` | 方法 | 共用 | 返回当前实例所在页的 pageId 字符串。 |
| `getOpenerEventChannel()` | 方法 | 页面 | 打开当前页的 `EventChannel`,组件侧多为空实现占位。 |
| `triggerEvent(name, detail?)` | 方法 | 组件 | 向父节点派发自定义事件。 |
| `selectComponent(selector)` | 方法 | 共用 | 按选择器取第一个匹配实例。RN 不能像小程序一样按 selector 遍历视图树,须在模板目标节点声明 **空 wx:ref**,由编译期建立 **`#id` / `.class` 与节点**的映射后,本 API 才能按小程序写法解析。 |
| `selectAllComponents(selector)` | 方法 | 共用 | 取全部匹配实例数组,**RN 侧与 `selectComponent` 相同**:依赖模板 **空 wx:ref** 与编译期 selector 映射,仅支持 **`#id` / `.class`**。 |
| `createSelectorQuery()` | 方法 | 共用 | 在实例作用域内创建查询对象。后续 **`select(selector)`** 等链式调用在 RN 上同样依赖目标节点 **空 wx:ref**,通过编译映射将 `#id` / `.class` 落到真实视图,以兼容小程序用法。 |
| `selectComponent(selector)` | 方法 | 共用 | 按选择器取第一个匹配实例。RN 不能像小程序一样按 selector 遍历视图树,须在模板目标组件声明 **空 wx:ref**,由编译期建立 **`#id` / `.class` 与组件**的映射后,本 API 才能按小程序写法解析。 |
| `selectAllComponents(selector)` | 方法 | 共用 | 取全部匹配实例数组,**RN 侧与 `selectComponent` 相同**:依赖模板组件 **空 wx:ref** 与编译期 selector 映射,仅支持 **`#id` / `.class`**。 |
| `createSelectorQuery()` | 方法 | 共用 | 在实例作用域内创建查询对象。后续 **`select(selector)`** 等链式调用在 RN 上同样依赖目标节点或组件 **空 wx:ref**,通过编译映射将 `#id` / `.class` 落到真实视图或组件,以兼容小程序用法。 |
| `createIntersectionObserver(options?)` | 方法 | 共用 | 在实例作用域内创建交叉观察。若相对某一节点观察且传入 **`#id` / `.class`**(如 `relativeTo` 等),RN 侧同样要求该节点模板已声明 **空 wx:ref** 并完成编译期映射,其余行为依赖 `@mpxjs/api-proxy` 的 RN 实现。 |
| `$refs` | 属性 | 共用 | 模板 **`wx:ref="refName"`** 对应的懒解析访问器(如 `this.$refs.refName`);**空 wx:ref 不会注册具名 ref**,但与 selector 映射可并存——需按名取子实例时再写 **`wx:ref="refName"`**。 |
| `$watch` | 方法 | 共用 | 动态创建对数据路径或表达式的侦听,返回用于停止侦听的函数,行为与选项式 `watch` 对齐。 |
Expand All @@ -195,13 +195,13 @@

#### 注意事项

- **`selectComponent`、`selectAllComponents`、`createSelectorQuery`(含 `select` 等链式入参)、`createIntersectionObserver`(`relativeTo` / `observe` 等涉及 selector 时)**在小程序中依赖视图层按 selector 查找节点,**RN 无同等原生能力**;须在**与 script 中 selector 对应**的节点上声明 **空 wx:ref**,可与 `id`、`class` 并存,由 **Mpx 编译期**根据 **`#id` / `.class` 建立映射**。若需 **`$refs` / `context.refs`** 按名访问,再使用 **`wx:ref="refName"`**。映射**仅支持 `#id` 与 `.class`**,不支持复合、后代等选择器;**未写 `wx:ref` 则无法解析**。`createSelectorQuery` / `createIntersectionObserver` 的测量与交叉等行为仍以 `@mpxjs/api-proxy` 的 RN 实现为准。
- **`selectComponent`、`selectAllComponents`、`createSelectorQuery`(含 `select` 等链式入参)、`createIntersectionObserver`(`relativeTo` / `observe` 等涉及 selector 时)**在小程序中依赖视图层按 selector 查找节点,**RN 无同等原生能力**;须在**与 script 中 selector 对应**的节点或组件上声明 **空 wx:ref**,可与 `id`、`class` 并存,由 **Mpx 编译期**根据 **`#id` / `.class` 建立映射**。若需 **`$refs` / `context.refs`** 按名访问,再使用 **`wx:ref="refName"`**。映射**仅支持 `#id` 与 `.class`**,不支持复合、后代等选择器;**未写 `wx:ref` 则无法解析**。`createSelectorQuery` 支持查询基础节点与自定义组件,自定义组件默认测量非 virtualHost 场景下的 host 根节点;`createIntersectionObserver` 的测量与交叉等行为仍以 `@mpxjs/api-proxy` 的 RN 实现为准。

**使用示例:**

```html
<template>
<!-- selector 相关 API:目标节点声明空 wx:ref;自定义组件须在 json 中注册后方可 selectComponent -->
<!-- selector 相关 API:目标节点或组件声明空 wx:ref;自定义组件须在 json 中注册后方可 selectComponent -->
<card id="chip" wx:ref />
<view id="box" class="block" wx:ref>内容</view>
<view class="cell" wx:ref>单元 1</view>
Expand Down Expand Up @@ -380,9 +380,9 @@ createComponent({
- `defineProps`、`defineExpose`、`defineOptions`、`useContext`、`withDefaults` 是编译宏,不需要从 `@mpxjs/core` 导入;`ref`、`computed`、生命周期钩子等运行时 API 仍需从 `@mpxjs/core` 命名导入。
- `defineProps()` 传入的运行时声明、`defineOptions()` 传入的构造选项会提升到模块作用域,不可引用 `<script setup>` 中的局部变量,可引用 import 进来的绑定。
- `<script setup>` 不支持和 `src` attribute 一起使用,也不支持通过 import 快捷引入组件;输出 RN 时使用 RN 原生组件请通过 `defineOptions({ components: { NativeView } })` 注册。
- 需要访问节点、组件实例或 selector 能力时,优先在 `onMounted` 及之后读取 `useContext().refs`;传入 `#id` / `.class` 的 selector 仍要在模板对应节点声明空 `wx:ref`,具名访问使用 `wx:ref="refName"`。
- 需要访问节点、组件实例或 selector 能力时,优先在 `onMounted` 及之后读取 `useContext().refs`;传入 `#id` / `.class` 的 selector 仍要在模板对应节点或组件声明空 `wx:ref`,具名访问使用 `wx:ref="refName"`。
- 组合式生命周期 **禁止在异步回调里注册**,否则会丢失当前实例上下文。
- `context.refs` 及 **`selectComponent` / `selectAllComponents` / `createSelectorQuery` / `createIntersectionObserver`** 在 RN 上与选项式相同:`refs` 在 `onMounted` 及之后更可靠,**凡传入 `#id` / `.class` 的用法均须在模板对应节点声明空 wx:ref**(具名访问用 `wx:ref="refName"`),详见「页面 / 组件实例方法与属性」注意事项。
- `context.refs` 及 **`selectComponent` / `selectAllComponents` / `createSelectorQuery` / `createIntersectionObserver`** 在 RN 上与选项式相同:`refs` 在 `onMounted` 及之后更可靠,**凡传入 `#id` / `.class` 的用法均须在模板对应节点或组件声明空 wx:ref**(具名访问用 `wx:ref="refName"`),详见「页面 / 组件实例方法与属性」注意事项。

---

Expand Down
7 changes: 4 additions & 3 deletions docs-vitepress/api-proxy/wxml/createSelectorQuery.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
[参考文档](https://developers.weixin.qq.com/miniprogram/dev/api/wxml/wx.createSelectorQuery.html)

### 特别说明RN中 {#rn-note}
1. 调用 createSelectorQuery 组件时,需要通过 wx:ref 进行绑定。
2. 调用 createSelectorQuery 方法创建的 SelectorQuery 实例, 在使用过程中需要手动调用实例上的 in 方法来指定组件上下文。
1. RN 中调用 createSelectorQuery 查询基础节点或自定义组件时,目标节点或组件需要通过空 `wx:ref` 进行绑定。
2. 调用 createSelectorQuery 方法创建的 SelectorQuery 实例,在使用过程中需要手动调用实例上的 in 方法来指定组件上下文。
3. 查询自定义组件时,默认测量非 virtualHost 场景下的 host 根节点。


### 返回值 {#return-value}
Expand All @@ -23,4 +24,4 @@ query.exec(function(res){
res[0].top // #the-id节点的上边界坐标
res[1].scrollTop // 显示区域的竖直滚动位置
}).in(this) // RN需要指定上下文,其他环境不强制
```
```
9 changes: 7 additions & 2 deletions docs-vitepress/guide/rn/application-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ module.exports = {

### 跨平台 API 使用限制 {#cross-platform-api-limit}
### selectComponent/selectAllComponents
在 RN 环境下使用 `selectComponent` 或 `selectAllComponents` 时,必须在目标节点上标记 wx:ref。选择器支持范围有限,仅支持以下方式
在 RN 环境下使用 `selectComponent` 或 `selectAllComponents` 时,必须在目标组件上标记 wx:ref。选择器支持范围有限,仅支持以下方式
* id 选择器:`#id`
* class 选择器(可连续指定多个):`.a-class` 或 `.a-class.b-class.c-class`

Expand All @@ -247,11 +247,12 @@ module.exports = {

#### createSelectorQuery

使用 `createSelectorQuery` 来获取基础组件需要在基础节点上标记 `wx:ref` 标签才能生效,以及所支持的选择器范围和 `selectComponent`/`selectAllComponents` 一致。
使用 `createSelectorQuery` 获取基础组件或自定义组件布局信息时,需要在目标节点或组件上标记空 `wx:ref` 标签才能生效,以及所支持的选择器范围和 `selectComponent`/`selectAllComponents` 一致。自定义组件默认会测量其非 virtualHost 场景下的 host 根节点

```javascript
<template>
<view wx:ref class="title">this is view</view>
<custom-card wx:ref class="card" />
</template>

<script>
Expand All @@ -264,6 +265,10 @@ module.exports = {
.boundingClientRect(res => {
console.log('the rect res is:', res)
})
.select('.card')
.boundingClientRect(res => {
console.log('the card rect res is:', res)
})
.exec()
}
})
Expand Down
4 changes: 2 additions & 2 deletions docs-vitepress/guide/rn/component.md
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@ Mpx 完全支持自定义组件功能,组件创建、属性配置、生命周
| id, dataset | ✅ 完全支持 | 节点基础属性 |
| setData | ✅ 完全支持 | 数据更新方法 |
| triggerEvent | ✅ 完全支持 | 事件触发 |
| createSelectorQuery | ✅ 有限制 | 返回一个 SelectorQuery 对象实例,用以查询基础节点位置等属性,需配合 `wx:ref` 使用 |
| createSelectorQuery | ✅ 有限制 | 返回一个 SelectorQuery 对象实例,用以查询基础节点或自定义组件位置等属性,需配合 `wx:ref` 使用;自定义组件默认测量非 virtualHost 场景下的 host 根节点 |
| selectComponent | ✅ 有限制 | 在父组件当中获取子组件的实例对象,返回匹配到的第一个组件实例,需配合 `wx:ref` 使用 |
| selectAllComponents | ✅ 有限制 | 在父组件当中获取子组件的实例对象,返回匹配到的全部组件实例对象组成的数组,需配合 `wx:ref` 使用 |
| $set, $watch, $delete | ✅ 完全支持 | 响应式数据操作 |
Expand All @@ -823,7 +823,7 @@ Mpx 完全支持自定义组件功能,组件创建、属性配置、生命周
#### selectComponent / selectAllComponents 使用要点 {#select-component-usage}

在 RN 环境下使用 `selectComponent` 或 `selectAllComponents` 时
1. 必须在目标节点上标记 `wx:ref`
1. 必须在目标组件上标记 `wx:ref`
2. 选择器支持范围有限,仅支持以下方式
- id 选择器 `#id`
- class 选择器 `.class` 或连续指定 `.a-class.b-class.c-class`
Expand Down
90 changes: 90 additions & 0 deletions packages/api-proxy/__tests__/rn/create-selector-query.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import SelectorQuery from '../../src/platform/api/create-selector-query/rnSelectQuery'

describe('createSelectorQuery for RN', () => {
test('select should support custom component refs', (done) => {
const componentRef = {
__getNodeInstance () {
return {
nodeRef: {
current: true
},
props: {
current: {}
},
instance: {
ref: 'custom-component-ref'
}
}
}
}
const component = {
__selectRef: jest.fn(() => componentRef)
}
const query = new SelectorQuery()

query.in(component).select('.custom').ref()
query.exec((res) => {
expect(component.__selectRef).toHaveBeenCalledWith('.custom', ['node', 'component'], undefined)
expect(res).toEqual([{ ref: 'custom-component-ref' }])
done()
})
})

test('select should support custom component refs by id', (done) => {
const componentRef = {
__getNodeInstance () {
return {
nodeRef: {
current: true
},
props: {
current: {}
},
instance: {
ref: 'custom-component-ref'
}
}
}
}
const component = {
__selectRef: jest.fn(() => componentRef)
}
const query = new SelectorQuery()

query.in(component).select('#custom').ref()
query.exec((res) => {
expect(component.__selectRef).toHaveBeenCalledWith('#custom', ['node', 'component'], undefined)
expect(res).toEqual([{ ref: 'custom-component-ref' }])
done()
})
})

test('selectAll should support custom component refs', (done) => {
const componentRefs = ['custom-component-ref-1', 'custom-component-ref-2'].map(ref => ({
__getNodeInstance () {
return {
nodeRef: {
current: true
},
props: {
current: {}
},
instance: {
ref
}
}
}
}))
const component = {
__selectRef: jest.fn(() => componentRefs)
}
const query = new SelectorQuery()

query.in(component).selectAll('.custom').ref()
query.exec((res) => {
expect(component.__selectRef).toHaveBeenCalledWith('.custom', ['node', 'component'], true)
expect(res).toEqual([[{ ref: 'custom-component-ref-1' }, { ref: 'custom-component-ref-2' }]])
done()
})
})
})
Loading
Loading