swiper / swiper-item — 实现与 components.md 对照
对照基准:
- 规格:docs/refs/components.md#swiper / swiper-item
- ASCF 官方:swiper / swiper-item
- Hippy 参考:swiper → ViewPager / swiper-slide → ViewPagerItem
- 实现:
packages/flexui-frontend/src/components/swiper/packages/flexui-frontend/src/components/swiper-item/flexui-engine/.../adapters/swiper-adapter.ts/swiper-item-adapter.ts- C++:
pager_view.cc/swiper_node.cc;ETS:FRViewPager.ets - Demo:
demos/ascf-ai-demo/.../swiper-demo/
模板 kebab-case;组件 properties camelCase;adapter / host 仅 kebab-case。
结论摘要
| 维度 | 结论 |
|---|---|
| 原生节点 | swiper → ViewPager;swiper-item → ViewPagerItem |
| 已贯通 | current、autoplay、interval、duration、circular、vertical、display-multiple-items、previous-margin、next-margin、disable-touch、indicator-dots、indicator-color、indicator-active-color + bindchange / bindtransition / bindanimationfinish |
item-id / currentItemId |
itemId 存于 ViewPagerItem;pageSelected / animationfinish 按当前 index 回填 currentItemId |
| Demo | 正向(含 indicator 配色切换、itemId 事件)+ 异常("false" 字符串 Boolean、非法 current / circular) |
属性对照
swiper
| 属性(模板) | 规格默认 | components.md | 当前实现 | 原生 / Hippy |
|---|---|---|---|---|
indicator-dots |
false |
✅ | ✅ → indicatorDots |
ArkUI indicator / SetShowIndicator |
indicator-color |
rgba(0,0,0,0.3) |
✅ | ✅ → ARGB → DotIndicator / OH_ArkUI_SwiperIndicator_SetColor |
adapter parseColorValue |
indicator-active-color |
#0A59F7 |
✅ | ✅ → ARGB → selectedColor / SetSelectedColor |
同上 |
current |
0 |
✅ | ✅ → current(首帧无动画;之后变更带动画) |
首帧/initialPage→SetSwiperIndex;其后 current→SwipeToIndex(...,1) / changeIndex(true);同 index 短路 |
autoplay |
false |
✅ | ✅ → autoPlay |
NODE_SWIPER_AUTO_PLAY / .autoPlay |
interval |
5000 |
✅ | ✅ | NODE_SWIPER_INTERVAL / .interval |
duration |
500 |
✅ | ✅ | NODE_SWIPER_DURATION / .duration(须配合非弹簧 curve,见下) |
circular |
false |
✅ | ✅ → circular/loop |
SetSwiperLoop / .loop |
vertical |
false |
✅ | ✅ | Hippy direction=vertical / .vertical |
display-multiple-items |
1 |
✅ | ✅ | NODE_SWIPER_DISPLAY_COUNT / .displayCount |
previous-margin |
"0px" |
✅ | ✅ → previousMargin |
SetSwiperPrevMargin |
next-margin |
"0px" |
✅ | ✅ → nextMargin |
SetSwiperNextMargin |
disable-touch |
false |
✅ | ✅ → disableTouch(= !scrollEnabled) |
Hippy scrollEnabled |
swiper-item
| 属性 | 规格 | 当前实现 |
|---|---|---|
item-id |
可选标识 | ✅ → itemId(C++/ETS 存储;事件按 index 查询) |
事件对照
| ASCF | Native wire | detail |
|---|---|---|
bindchange |
pageSelected(wire: pageselected) |
{ current, currentItemId, source }:source=touch/autoplay/""(setData·setPage 等) |
bindtransition |
pageScroll(wire: pagescroll) |
{ dx, dy }(横向 offset→dx;纵向 offset→dy;payload 带 vertical) |
bindanimationfinish |
animationfinish(OnAnimationEnd) |
{ current, currentItemId, source }(与 change 同源) |
组件 def 不声明
events:FlexUI 无该字段;监听由模板bind:*→ NBEsetListenerStats+ adaptereventNamesMap注册(与 scroll-view 相同)。
实现要点
- Boolean
!!/ Number 串:optionalTypes:[String]接住模板属性串(含interval="{{5000}}")。Boolean 字符串"false"按!!为真(异常 Demo)。Number 非法串(如interval="abc")仍回退默认值;dev(NODE_ENV !== 'production')下triggerWarning提示,production 静默。 - margin:adapter 解析
px/rpx→ 逻辑 px,再交 nativeDpToVp。rpx 复用FlexUIBridge.getDimensions().width / 750(与 StyleResolver 约定一致;dims 缺失时 width fallback=375,等价旧/2)。样式路径的 rpx 字符串仍透传 native;此处因 margin 属性走 float prop,必须在 JS 侧先换算。 - 改 adapter / frontend →
compile-builtins+ frontend build +build-jsfwk;改 C++/ETS → HAP - LITE 白名单:
build-profile.json5的LITE_COMPONENTS与BuildConfig.ets必须包含ViewPager,ViewPagerItem,否则CreateRenderView返回空 → Demo 空白 - displayCount>1 / 纵向均分 — 强依赖 NBE Yoga %(C++/ETS 不自行按 N 算格子主轴)
- NBE:
NativeBackendElement._applyViewPagerItemSlotSize读父级display-multiple-items+vertical,把 item 主轴写成100/N%(横→width,纵→height),交叉轴缺省100%。setData改 display/vertical 后靠每次resolveNativeProps覆盖生效。 - C++
PagerItemView:SetHeight(frame.height)+SetWidthPercent(1.0)—— 高度/Yoga 帧来自上游;不读displayCount_做纵向heightPercent。 - ETS
FRViewPagerItem:cssHeight = frame.height,再.width('100%').height(cssHeight)—— 同上。 - 结论:
vertical && display-multiple-items>1时格子主轴尺寸只靠 NBE Yoga%;缺_applyViewPagerItemSlotSize或%未进 Yoga,C++/ETS 无法补救,子树仍按整页排版并裁切。swiper-item禁止position:absolute全铺。
- NBE:
- current:首帧 /
initialPage→ C++SetSwiperIndex、ETSchangeIndex(false)(无动画);之后的current变更 →SwipeToIndex(i,1)/changeIndex(true)。同 index 短路(挡住 onChange→setData 回灌)。C++ 先写index_;ETS 动画路径先写pendingIndex做短路,this.index仍由onChange→settleIndex回写(避免.index()绑定冲动画) - indicator 配色:adapter
parseColorValue→ ARGB;C++NODE_SWIPER_INDICATOR+OH_ArkUI_SwiperIndicator_SetColor/SetSelectedColor;ETSIndicator.dot().color().selectedColor() - currentItemId:子项存
itemId;pageSelected/animationfinish按当前 index 查子项回填 - source:Touch Down →
touch;无 touch 且autoPlay→autoplay;current/setPage等程序切页 →""。pageSelected每次重算写入;animationfinish读同轮值后清空,避免下一轮仍报上一轮touch - 事件名 wire:JS
eventNamesMap必须用小写 wire 名(pageselected/pagescroll)。DispatchEvent会 toLowerCase;驼峰pageSelected会导致 reverse map 失败、bindchange不触发。 - 手势
bindchange:ETS 受控.index()下拖动常不回调onChange;onAnimationEnd在落点 ≠ 已 settle index 时补发pageSelected(与程序切页 onChange 去重,取消回弹不发)。 - 勿把 ViewPager 加进
ETS_ONLY_RENDER_VIEWS(C++ 已注册) - duration:ArkUI Swiper 默认
interpolatingSpring不受duration控制;ETS.curve(Curve.Linear)/ C++NODE_SWIPER_CURVE=LINEAR,ASCFduration(ms)才生效。 - bindtransition:native
pageScroll;ETSonContentDidScroll(滑动全程)+onAnimationEnd在|offset|≤0.05时补发终态pageScroll(offset=0)(对齐 C++);JS 须transition→pagescroll。
Demo 覆盖
- 正向:华为示例动态面板(dots / 配色 / autoplay / circular / vertical / current / interval / duration / display / margins / disable-touch)+ 三事件(status 展示
itemId) - 异常:
autoplay="false"、current="abc"、vertical="false"、circular="abc"