WeChat Mini Program Development
Goal
Build maintainable WeChat Mini Program features quickly while preserving the project's existing architecture and coding style.
Workflow
- Confirm project conventions before coding.
- Implement with native Mini Program patterns first.
- Verify data/event flow end-to-end.
- Keep changes small, composable, and easy to review.
1) Read Context First
- Inspect related files in this order:
page/index.json -> page/index.wxml -> page/index.js -> page/index.scss|wxss.
- Check shared utilities and component dependencies before adding new logic:
src/utils/*, src/components/*, app.json, page usingComponents.
- Reuse existing naming and folder patterns; avoid introducing a parallel style.
2) Preferred Implementation Rules
- Prefer extracting reusable UI into components when a block has clear boundaries.
- Keep page as orchestration layer:
- page owns data source/state transitions,
- component owns local rendering and emits events.
- Use explicit custom events and stable payloads:
this.triggerEvent('event-name', { ...detail })
- page reads from
event.detail, not event.currentTarget.dataset for child events.
- When handling toggle/select lists, update with immutable map operations to avoid index/state drift.
3) WXML / WXSS Guidance
- Avoid web-only patterns that don't map cleanly to Mini Program runtime.
- Keep template readable:
- extract heavy conditional branches into components,
- avoid oversized inline logic in a single page template.
- Keep class naming consistent with project conventions.
- If the project uses utility classes (e.g., Tailwind-like), continue using them consistently.
4) Page/Component Contracts
When creating a component, always define:
properties: typed inputs with safe defaults.
methods: user actions and event emitters.
index.json usingComponents: only required dependencies.
- local styles in component
index.scss|wxss.
Recommended event contract:
permissiontap -> { index }
permissionchange -> { index, value }
- action events like
accept / reject with no extra payload when unnecessary.
5) Common Tasks Checklist
Extract block into component
- Move WXML block to
src/components/<Name>/index.wxml.
- Move block-specific styles to component stylesheet.
- Create component
index.js with properties + triggerEvent methods.
- Register component in page
index.json.
- Replace original block with component tag and bind events.
- Update page handlers to consume
event.detail.
Convert web snippet to Mini Program
- Replace DOM/web attributes with WXML-compatible equivalents.
- Replace unsupported interactions with
bindtap, catchtap, and component events.
- Keep semantics and visual hierarchy, then adapt syntax.
Debug interaction/data issues
- Validate source of truth in page
data.
- Check whether change path is:
user interaction -> component method -> triggerEvent -> page handler ->
setData.
- Check
data-* / event.detail mismatch first; this is a common break point.
5.1) PRD HTML Popup Refactor Pattern
- For multi-branch popup content (
wx:if / wx:elif / wx:else), extract each heavy branch into an isolated component instead of keeping one giant page template.
- Keep page as orchestration layer:
- page maintains branch type and popup payload object (for example
riskPopup),
- component receives one typed object property (for example
riskData) and only renders.
- Convert copied web markup aggressively:
- replace
div/span/h* with view/text,
- replace
img with image or t-image,
- replace inline
svg with t-icon.
- Validate icon names before finalizing:
- check
node_modules/tdesign-miniprogram/miniprogram_dist/icon/icon.wxss.
- If a branch lacks a trigger in current data, add a temporary/mock entry (for example
type: 'risk') so the branch can be verified end-to-end.
6) Quality Bar
Before finishing, verify:
- Component/page responsibilities are clear.
usingComponents is complete and minimal.
- No dead handlers remain after extraction.
- Data updates still drive expected UI states.
- No raw HTML tags (
<div>, <svg>, <img>) remain in final WXML.
- Files stay ASCII unless existing file already uses non-ASCII intentionally.
7) Output Style
When delivering changes:
- Start with what was built/refactored.
- List touched files.
- Call out event/data contract changes explicitly.
- Mention any verification gaps (if runtime not executed).
References
- Read wechat-guidelines.md for a compact implementation checklist and reusable prompts.
- Read page-pr-checklist.md before finishing page-level PRs to avoid route/loop/template regressions.
8) Popup Branch Refactor Lessons
When converting or adding reminder popup branches (for example risk / exercise / sleep), follow this pattern to avoid regressions:
- Keep page as orchestration only:
- page decides branch type (
currentRemindType) and owns popup data objects (riskPopup, exercisePopup, sleepPopup),
- branch component receives one object prop and renders only.
- Never keep raw web HTML in page popup branches:
- remove
<div>, <span>, <h*>, <svg> from WXML branch blocks,
- replace with component tags +
t-icon.
- Add branch support as a complete set, not partially:
- add component files,
- register in page
usingComponents,
- add page data object,
- wire branch rendering in popup
wx:elif.
- Validate icon names from local
tdesign-miniprogram icon definitions before finalizing.
- After edits, run a quick raw-tag scan on touched WXML:
- check for
<div|<svg|<span|<h and clean remaining web-only tags.
- Keep a safe fallback branch (
wx:else) in popup when product allows it, so unknown types do not render blank content.
9) Editing Reliability Notes
When patching JSON/JS/WXML in bulk:
- Prefer structural edits over brittle string replacement that can inject literal escape artifacts (for example accidental
`n in JSON).
- Re-open modified files immediately and verify syntax/format after scripted replacements.
- If a scripted replacement corrupts formatting, rewrite the full file content once to restore canonical structure.
10) Popup Scroll Ownership (Important)
When popup content is long in WeChat Mini Program, keep one and only one vertical scroll owner.
- For
t-popup content that can exceed viewport height, assign exactly one scroll container.
- Preferred page-level pattern:
- wrap popup content with
<scroll-view type="list" scroll-y style="height: 80vh">...</scroll-view>.
- If page-level wrapper is the scroll owner, remove component-internal scroll constraints:
- remove nested
<scroll-view> in the child component,
- remove
max-height / overflow-y on the component root when they duplicate scrolling.
- Avoid mixed nested scroll systems (
scroll-view + CSS overflow-y) for the same axis; this commonly causes no-scroll or gesture conflicts.
- Keep the same popup family on one scroll pattern so behavior is predictable across branches.
- If a fixed header is required inside popup, split structure into
header + scroll body instead of making the entire popup node scroll.
Quick debug checklist when popup cannot scroll:
- Confirm content actually overflows target height (
70vh/80vh).
- Check there is no competing parent/child vertical scroll container.
- Check whether
prevent-scroll-through is enabled and whether internal scroll owner still receives gestures.
- Reproduce on device and DevTools; nested scroll conflicts are often device-sensitive.
11) Component-Local Popup Pattern
For detail popups launched from reusable components (for example a person card "AI insight" entry):
- Keep responsibilities clear:
- component owns popup visibility and close/open methods,
- page remains orchestration only for cross-component concerns.
- Use explicit event hooks for observability without coupling:
- component may
triggerEvent('insightopen') and triggerEvent('insightclose'),
- page can listen when needed, but should not be forced to mirror popup UI state.
- Normalize PRD rich text to typed data:
- use arrays like
analysisList -> [{ id, dotColor, parts: [{ text, tone }] }],
- render with
wx:for and class variants instead of hardcoded repeated blocks.
- Keep one vertical scroll owner in popup content:
- recommended: popup root with fixed header + one content
scroll-view,
- avoid mixed
sticky + nested scroll-view + overflow-y combinations.
- Verification checklist for this pattern:
t-popup is registered in component usingComponents,
- popup opens from
bindtap on trigger row and can close by overlay/button,
- no raw web tags (
<div>, <svg>) remain in converted WXML branch.
12) Page Entry Navigation Checklist
For “click card -> open new page” requirements, enforce this three-point check together:
- WXML entry node has
bindtap and a clear handler name.
- Page JS implements the handler with
wx.navigateTo({ url }).
- Target page path is registered in
src/app.json pages (for non-tab pages).
If any one is missing, navigation will silently fail or report route-not-found.
13) Nested wx:for Safety
When templates contain nested loops:
- Always define
wx:for-item for the inner loop (for example nutrient) and avoid alias reuse with outer loop items.
- Keep display classes split by semantic target (
tag, icon, value), rather than reusing one mixed class string.
- Prefer putting loop config in page
data arrays to keep template logic thin and maintainable.
14) Period Switch Split-Render Pattern
For requirements like "keep day old layout, migrate only week/month/year to new PRD layout":
- Use page-level conditional rendering:
wx:if="{{ activePeriod === 'day' }}" for legacy day block,
wx:else (or explicit branches) for the new report component.
- Keep page as orchestration layer:
updatePeriodContent(period) decides branch and calls setData,
- component only renders incoming
reportData.
- Maintain separate sources of truth to avoid coupling:
sections for day list cards,
reportDataMap (plus optional normalize/decorate step) for period reports.
- Keep
usingComponents complete after refactor:
- include both legacy dependencies (
remind-card, t-icon) and new component registration.
- Preserve backwards-compatible styles for legacy branch and avoid leaking overrides into new component styles.
- Quick verification checklist:
- each tab renders expected structure,
- switch state does not retain stale data from previous branch,
- no removed handler/component is still referenced in WXML.
15) Tailwind Extraction Safety (Important)
When a project uses Tailwind-like utilities in Mini Program:
- Keep key utility classes literal in
wxml whenever possible; avoid hiding core layout/visual classes inside JS-only strings.
- Assume dynamic class strings in
data (item.className) may be dropped by extraction in some pipelines; if used, verify generated CSS explicitly.
- Prefer simple, deterministic rendering for repeated blocks:
- keep structure in
wx:for,
- keep critical classes static in template nodes,
- move unstable variants to
scss fallback classes when necessary.
- For unsupported or weakly-supported web behaviors (hover groups, advanced filters, list marker semantics on
view), implement Mini Program-native fallback instead of forcing parity.
- Add a quick production-artifact check before finishing:
- search
dist/app.wxss for several must-have classes from the touched page,
- if missing, rewrite to static classes or add scoped
scss equivalents.
16) Center Popup Debug Pattern (Blank Content)
For issues like "popup opened but content area is blank", run this debug sequence:
- Confirm visibility contract first:
- page data has
popupVisible,
- open action sets it to
true,
t-popup visible="{{popupVisible}}" is bound correctly.
- If popup content uses
scroll-view, prefer explicit inline height immediately:
<scroll-view type="list" scroll-y style="height: 80vh">...</scroll-view>.
- Avoid ambiguous first-pass constraints (
max-height only, nested Y-scroll containers, or mixed overflow-y + scroll-view).
- For popup list/item styles driven by data class names, keep these classes in popup component
index.scss|wxss to avoid cross-file style coupling.
- Avoid critical
wxml array-index interpolation for popup labels (for example {{relationOptions[relationIndex]}}); keep a synchronized display field in data (for example selectedRelation).
- In popup component
properties observers, prefer direct setData initialization for open-state reset; avoid observer calling another method as the only first-render path.
- Make popup root container style explicit in component stylesheet (
background, border-radius, overflow, width, shadow) to avoid root utility-class loss causing invisible body.
- For center popup
scroll-view, apply both fixed height and max-height in first pass (for example height: 960rpx; max-height: 76vh;), then refine after device verification.
- Validate close behavior symmetry:
- overlay close (
bind:visible-change) and explicit close button event should both reset the same page state.
- Fast isolation trick:
- temporarily replace popup body with a static
<view> block;
- if visible, issue is scroll/layout constraints, not popup registration.
17) Tailwind-First + view/text Contract
For projects using Tailwind-like utility classes, keep this node contract strict:
- Preserve utility classes in WXML first; avoid rewriting to custom SCSS too early.
- If a node has layout/box styling (
px/py, rounded, border, w/h, flex, margin/padding/display), that node should be view, not text.
- Use
text for pure text semantics; for version badges/chips, use:
- outer
view with layout/background/border classes,
- inner
text with font/color classes.
- Add a quick pre-delivery check on touched files:
- scan for
text nodes carrying obvious layout utility classes,
- convert to
view wrappers to reduce cross-device rendering issues.
18) Version Display Data Source Pattern
When a page needs "current mini program version", avoid hardcoded constants as source of truth:
- Read from
wx.getAccountInfoSync().miniProgram.version first.
- Normalize format to
v* when needed (for example 2.1.0 -> v2.1.0).
- Provide fallback for non-release env:
develop -> 开发版,
trial -> 体验版,
- final fallback to a safe default constant.
- Put this logic in shared
src/utils helper and reuse across pages (for example About + Version pages) to keep behavior consistent.
19) One-Pass Delivery Checklist for New Page Tasks
For "click entry -> navigate to new page" requirements, finish all dependencies in one pass:
- Entry handler:
bindtap + page JS wx.navigateTo.
- Route registration: target page added in
src/app.json.
- New page files complete:
index.json/wxml/js/scss.
- Component extraction complete when used: each component has
js/json/wxml/scss + page usingComponents.
- Run final sanity check that styles are not missing due to absent
index.scss or missing component registration.
1---2name: wechat-miniprogram-development3description: Implement, refactor, and troubleshoot WeChat Mini Program features using native project conventions (pages/components/wxml/wxss/js/json), event/data binding, and common ecosystem practices (e.g., TDesign, request封装, 分包与性能优化). Use this skill whenever the user asks to build pages/components, convert web snippets to 小程序, fix rendering or interaction bugs, optimize data flow, or align code with 微信小程序开发规范.4---56# WeChat Mini Program Development78## Goal910Build maintainable WeChat Mini Program features quickly while preserving the project's existing architecture and coding style.1112## Workflow13141. Confirm project conventions before coding.152. Implement with native Mini Program patterns first.163. Verify data/event flow end-to-end.174. Keep changes small, composable, and easy to review.1819## 1) Read Context First2021- Inspect related files in this order:22 `page/index.json` -> `page/index.wxml` -> `page/index.js` -> `page/index.scss|wxss`.23- Check shared utilities and component dependencies before adding new logic:24 `src/utils/*`, `src/components/*`, `app.json`, page `usingComponents`.25- Reuse existing naming and folder patterns; avoid introducing a parallel style.2627## 2) Preferred Implementation Rules2829- Prefer extracting reusable UI into components when a block has clear boundaries.30- Keep page as orchestration layer:31 - page owns data source/state transitions,32 - component owns local rendering and emits events.33- Use explicit custom events and stable payloads:34 - `this.triggerEvent('event-name', { ...detail })`35 - page reads from `event.detail`, not `event.currentTarget.dataset` for child events.36- When handling toggle/select lists, update with immutable map operations to avoid index/state drift.3738## 3) WXML / WXSS Guidance3940- Avoid web-only patterns that don't map cleanly to Mini Program runtime.41- Keep template readable:42 - extract heavy conditional branches into components,43 - avoid oversized inline logic in a single page template.44- Keep class naming consistent with project conventions.45- If the project uses utility classes (e.g., Tailwind-like), continue using them consistently.4647## 4) Page/Component Contracts4849When creating a component, always define:5051- `properties`: typed inputs with safe defaults.52- `methods`: user actions and event emitters.53- `index.json` `usingComponents`: only required dependencies.54- local styles in component `index.scss|wxss`.5556Recommended event contract:5758- `permissiontap` -> `{ index }`59- `permissionchange` -> `{ index, value }`60- action events like `accept` / `reject` with no extra payload when unnecessary.6162## 5) Common Tasks Checklist6364### Extract block into component6566- Move WXML block to `src/components/<Name>/index.wxml`.67- Move block-specific styles to component stylesheet.68- Create component `index.js` with properties + triggerEvent methods.69- Register component in page `index.json`.70- Replace original block with component tag and bind events.71- Update page handlers to consume `event.detail`.7273### Convert web snippet to Mini Program7475- Replace DOM/web attributes with WXML-compatible equivalents.76- Replace unsupported interactions with `bindtap`, `catchtap`, and component events.77- Keep semantics and visual hierarchy, then adapt syntax.7879### Debug interaction/data issues8081- Validate source of truth in page `data`.82- Check whether change path is:83 user interaction -> component method -> triggerEvent -> page handler -> `setData`.84- Check `data-*` / `event.detail` mismatch first; this is a common break point.8586## 5.1) PRD HTML Popup Refactor Pattern8788- For multi-branch popup content (`wx:if` / `wx:elif` / `wx:else`), extract each heavy branch into an isolated component instead of keeping one giant page template.89- Keep page as orchestration layer:90 - page maintains branch type and popup payload object (for example `riskPopup`),91 - component receives one typed object property (for example `riskData`) and only renders.92- Convert copied web markup aggressively:93 - replace `div/span/h*` with `view/text`,94 - replace `img` with `image` or `t-image`,95 - replace inline `svg` with `t-icon`.96- Validate icon names before finalizing:97 - check `node_modules/tdesign-miniprogram/miniprogram_dist/icon/icon.wxss`.98- If a branch lacks a trigger in current data, add a temporary/mock entry (for example `type: 'risk'`) so the branch can be verified end-to-end.99## 6) Quality Bar100101Before finishing, verify:102103- Component/page responsibilities are clear.104- `usingComponents` is complete and minimal.105- No dead handlers remain after extraction.106- Data updates still drive expected UI states.107- No raw HTML tags (`<div>`, `<svg>`, `<img>`) remain in final WXML.108- Files stay ASCII unless existing file already uses non-ASCII intentionally.109110## 7) Output Style111112When delivering changes:113114- Start with what was built/refactored.115- List touched files.116- Call out event/data contract changes explicitly.117- Mention any verification gaps (if runtime not executed).118119## References120121- Read [wechat-guidelines.md](references/wechat-guidelines.md) for a compact implementation checklist and reusable prompts.122- Read [page-pr-checklist.md](references/page-pr-checklist.md) before finishing page-level PRs to avoid route/loop/template regressions.123124## 8) Popup Branch Refactor Lessons125126When converting or adding reminder popup branches (for example `risk` / `exercise` / `sleep`), follow this pattern to avoid regressions:127128- Keep page as orchestration only:129 - page decides branch type (`currentRemindType`) and owns popup data objects (`riskPopup`, `exercisePopup`, `sleepPopup`),130 - branch component receives one object prop and renders only.131- Never keep raw web HTML in page popup branches:132 - remove `<div>`, `<span>`, `<h*>`, `<svg>` from WXML branch blocks,133 - replace with component tags + `t-icon`.134- Add branch support as a complete set, not partially:135 - add component files,136 - register in page `usingComponents`,137 - add page data object,138 - wire branch rendering in popup `wx:elif`.139- Validate icon names from local `tdesign-miniprogram` icon definitions before finalizing.140- After edits, run a quick raw-tag scan on touched WXML:141 - check for `<div|<svg|<span|<h` and clean remaining web-only tags.142- Keep a safe fallback branch (`wx:else`) in popup when product allows it, so unknown types do not render blank content.143144## 9) Editing Reliability Notes145146When patching JSON/JS/WXML in bulk:147148- Prefer structural edits over brittle string replacement that can inject literal escape artifacts (for example accidental `` `n `` in JSON).149- Re-open modified files immediately and verify syntax/format after scripted replacements.150- If a scripted replacement corrupts formatting, rewrite the full file content once to restore canonical structure.151152## 10) Popup Scroll Ownership (Important)153154When popup content is long in WeChat Mini Program, keep one and only one vertical scroll owner.155156- For `t-popup` content that can exceed viewport height, assign exactly one scroll container.157- Preferred page-level pattern:158 - wrap popup content with `<scroll-view type="list" scroll-y style="height: 80vh">...</scroll-view>`.159- If page-level wrapper is the scroll owner, remove component-internal scroll constraints:160 - remove nested `<scroll-view>` in the child component,161 - remove `max-height` / `overflow-y` on the component root when they duplicate scrolling.162- Avoid mixed nested scroll systems (`scroll-view` + CSS `overflow-y`) for the same axis; this commonly causes no-scroll or gesture conflicts.163- Keep the same popup family on one scroll pattern so behavior is predictable across branches.164- If a fixed header is required inside popup, split structure into `header` + `scroll body` instead of making the entire popup node scroll.165166Quick debug checklist when popup cannot scroll:167168- Confirm content actually overflows target height (`70vh`/`80vh`).169- Check there is no competing parent/child vertical scroll container.170- Check whether `prevent-scroll-through` is enabled and whether internal scroll owner still receives gestures.171- Reproduce on device and DevTools; nested scroll conflicts are often device-sensitive.172173## 11) Component-Local Popup Pattern174175For detail popups launched from reusable components (for example a person card "AI insight" entry):176177- Keep responsibilities clear:178 - component owns popup visibility and close/open methods,179 - page remains orchestration only for cross-component concerns.180- Use explicit event hooks for observability without coupling:181 - component may `triggerEvent('insightopen')` and `triggerEvent('insightclose')`,182 - page can listen when needed, but should not be forced to mirror popup UI state.183- Normalize PRD rich text to typed data:184 - use arrays like `analysisList -> [{ id, dotColor, parts: [{ text, tone }] }]`,185 - render with `wx:for` and class variants instead of hardcoded repeated blocks.186- Keep one vertical scroll owner in popup content:187 - recommended: popup root with fixed header + one content `scroll-view`,188 - avoid mixed `sticky + nested scroll-view + overflow-y` combinations.189- Verification checklist for this pattern:190 - `t-popup` is registered in component `usingComponents`,191 - popup opens from `bindtap` on trigger row and can close by overlay/button,192 - no raw web tags (`<div>`, `<svg>`) remain in converted WXML branch.193194## 12) Page Entry Navigation Checklist195196For “click card -> open new page” requirements, enforce this three-point check together:197198- WXML entry node has `bindtap` and a clear handler name.199- Page JS implements the handler with `wx.navigateTo({ url })`.200- Target page path is registered in `src/app.json` `pages` (for non-tab pages).201202If any one is missing, navigation will silently fail or report route-not-found.203204## 13) Nested `wx:for` Safety205206When templates contain nested loops:207208- Always define `wx:for-item` for the inner loop (for example `nutrient`) and avoid alias reuse with outer loop items.209- Keep display classes split by semantic target (`tag`, `icon`, `value`), rather than reusing one mixed class string.210- Prefer putting loop config in page `data` arrays to keep template logic thin and maintainable.211212## 14) Period Switch Split-Render Pattern213214For requirements like "keep `day` old layout, migrate only `week/month/year` to new PRD layout":215216- Use page-level conditional rendering:217 - `wx:if="{{ activePeriod === 'day' }}"` for legacy day block,218 - `wx:else` (or explicit branches) for the new report component.219- Keep page as orchestration layer:220 - `updatePeriodContent(period)` decides branch and calls `setData`,221 - component only renders incoming `reportData`.222- Maintain separate sources of truth to avoid coupling:223 - `sections` for day list cards,224 - `reportDataMap` (plus optional normalize/decorate step) for period reports.225- Keep `usingComponents` complete after refactor:226 - include both legacy dependencies (`remind-card`, `t-icon`) and new component registration.227- Preserve backwards-compatible styles for legacy branch and avoid leaking overrides into new component styles.228- Quick verification checklist:229 - each tab renders expected structure,230 - switch state does not retain stale data from previous branch,231 - no removed handler/component is still referenced in WXML.232233## 15) Tailwind Extraction Safety (Important)234235When a project uses Tailwind-like utilities in Mini Program:236237- Keep key utility classes literal in `wxml` whenever possible; avoid hiding core layout/visual classes inside JS-only strings.238- Assume dynamic class strings in `data` (`item.className`) may be dropped by extraction in some pipelines; if used, verify generated CSS explicitly.239- Prefer simple, deterministic rendering for repeated blocks:240 - keep structure in `wx:for`,241 - keep critical classes static in template nodes,242 - move unstable variants to `scss` fallback classes when necessary.243- For unsupported or weakly-supported web behaviors (hover groups, advanced filters, list marker semantics on `view`), implement Mini Program-native fallback instead of forcing parity.244- Add a quick production-artifact check before finishing:245 - search `dist/app.wxss` for several must-have classes from the touched page,246 - if missing, rewrite to static classes or add scoped `scss` equivalents.247248## 16) Center Popup Debug Pattern (Blank Content)249250For issues like "popup opened but content area is blank", run this debug sequence:251252- Confirm visibility contract first:253 - page data has `popupVisible`,254 - open action sets it to `true`,255 - `t-popup visible="{{popupVisible}}"` is bound correctly.256- If popup content uses `scroll-view`, prefer explicit inline height immediately:257 - `<scroll-view type="list" scroll-y style="height: 80vh">...</scroll-view>`.258- Avoid ambiguous first-pass constraints (`max-height` only, nested Y-scroll containers, or mixed `overflow-y + scroll-view`).259- For popup list/item styles driven by data class names, keep these classes in popup component `index.scss|wxss` to avoid cross-file style coupling.260- Avoid critical `wxml` array-index interpolation for popup labels (for example `{{relationOptions[relationIndex]}}`); keep a synchronized display field in data (for example `selectedRelation`).261- In popup component `properties` observers, prefer direct `setData` initialization for open-state reset; avoid observer calling another method as the only first-render path.262- Make popup root container style explicit in component stylesheet (`background`, `border-radius`, `overflow`, width, shadow) to avoid root utility-class loss causing invisible body.263- For center popup `scroll-view`, apply both fixed height and `max-height` in first pass (for example `height: 960rpx; max-height: 76vh;`), then refine after device verification.264- Validate close behavior symmetry:265 - overlay close (`bind:visible-change`) and explicit close button event should both reset the same page state.266- Fast isolation trick:267 - temporarily replace popup body with a static `<view>` block;268 - if visible, issue is scroll/layout constraints, not popup registration.269270## 17) Tailwind-First + `view/text` Contract271272For projects using Tailwind-like utility classes, keep this node contract strict:273274- Preserve utility classes in WXML first; avoid rewriting to custom SCSS too early.275- If a node has layout/box styling (`px/py`, `rounded`, `border`, `w/h`, `flex`, margin/padding/display), that node should be `view`, not `text`.276- Use `text` for pure text semantics; for version badges/chips, use:277 - outer `view` with layout/background/border classes,278 - inner `text` with font/color classes.279- Add a quick pre-delivery check on touched files:280 - scan for `text` nodes carrying obvious layout utility classes,281 - convert to `view` wrappers to reduce cross-device rendering issues.282283## 18) Version Display Data Source Pattern284285When a page needs "current mini program version", avoid hardcoded constants as source of truth:286287- Read from `wx.getAccountInfoSync().miniProgram.version` first.288- Normalize format to `v*` when needed (for example `2.1.0` -> `v2.1.0`).289- Provide fallback for non-release env:290 - `develop` -> `开发版`,291 - `trial` -> `体验版`,292 - final fallback to a safe default constant.293- Put this logic in shared `src/utils` helper and reuse across pages (for example About + Version pages) to keep behavior consistent.294295## 19) One-Pass Delivery Checklist for New Page Tasks296297For "click entry -> navigate to new page" requirements, finish all dependencies in one pass:298299- Entry handler: `bindtap` + page JS `wx.navigateTo`.300- Route registration: target page added in `src/app.json`.301- New page files complete: `index.json/wxml/js/scss`.302- Component extraction complete when used: each component has `js/json/wxml/scss` + page `usingComponents`.303- Run final sanity check that styles are not missing due to absent `index.scss` or missing component registration.