hookehuyr

fix(ui): 修复搜索栏背景色和弹窗嵌套导致的层级问题

- 为搜索栏添加白色背景,避免在深色模式下显示异常
- 将 SchemeA 组件中的行业选择器弹窗提升到外层,避免嵌套弹窗在真机上的层级冲突
- 更新 lessons-learned 文档,记录弹窗嵌套问题的解决方案
...@@ -178,12 +178,62 @@ setTimeout(() => { ...@@ -178,12 +178,62 @@ setTimeout(() => {
178 <IconFont :name="iconName" :key="iconName" /> 178 <IconFont :name="iconName" :key="iconName" />
179 ``` 179 ```
180 180
181 +### ❌ 坑 3: 嵌套 nut-popup 导致真机层级冲突
182 +
183 +**问题描述**:
184 +```vue
185 +<!-- ❌ 真机测试时,内层弹窗被外层弹窗的底部按钮遮挡 -->
186 +<PlanPopup title="申请计划书">
187 + <!-- 表单内容 -->
188 +
189 + <!-- 嵌套的弹窗 -->
190 + <nut-popup position="bottom" v-model:visible="showIndustryPicker">
191 + <nut-picker :columns="industryColumns" />
192 + </nut-popup>
193 +</PlanPopup>
194 +```
195 +
196 +**场景**: SchemeA 组件使用 PlanPopup 容器(外层 nut-popup),内部再嵌套一个行业选择器(内层 nut-popup)
197 +
198 +**原因**:
199 +1. **小程序渲染机制**: 微信小程序的双线程渲染导致嵌套弹窗的层级处理异常
200 +2. **渲染上下文**: 外层 `nut-popup` 创建了独立的渲染上下文,内层即使设置更高 `z-index` 也可能被遮挡
201 +3. **DOM 顺序**: 外层弹窗的底部按钮在 DOM 中位于内层弹窗之后,真机渲染时可能覆盖
202 +
203 +**解决方案**: 将内层弹窗提升到外层弹窗外部
204 +```vue
205 +<!-- ✅ 正确:弹窗并列,不嵌套 -->
206 +<PlanPopup title="申请计划书">
207 + <!-- 表单内容 -->
208 +</PlanPopup>
209 +
210 +<!-- 内层弹窗提升到外层,设置更高的 z-index -->
211 +<nut-popup
212 + position="bottom"
213 + v-model:visible="showIndustryPicker"
214 + :z-index="9999"
215 + :overlay="true"
216 +>
217 + <nut-picker :columns="industryColumns" />
218 +</nut-popup>
219 +```
220 +
221 +**关键点**:
222 +- ✅ 将内层 `nut-popup` 移到外层组件外部
223 +- ✅ 设置 `:z-index="9999"` 确保显示在最上层
224 +- ✅ 保持 DOM 顺序:外层弹窗 → 内层弹窗(后渲染的在上层)
225 +
226 +**适用场景**:
227 +- 任何需要在 `nut-popup` 内部再使用 `nut-popup` 的情况
228 +- 特别是选择器(Picker)、对话框(Dialog)等弹窗组件
229 +
181 ### ✅ NutUI 最佳实践 230 ### ✅ NutUI 最佳实践
182 231
183 1. **优先使用原生组件**: 当 NutUI 组件样式限制时 232 1. **优先使用原生组件**: 当 NutUI 组件样式限制时
184 2. **添加 key 属性**: 动态切换图标时 233 2. **添加 key 属性**: 动态切换图标时
185 -3. **深度样式覆盖**: 尝试 `:deep()` 选择器 234 +3. **避免嵌套弹窗**: 始终将内层弹窗提升到外层外部
186 -4. **查阅文档**: 确认 NutUI 版本和已知问题 235 +4. **深度样式覆盖**: 尝试 `:deep()` 选择器
236 +5. **查阅文档**: 确认 NutUI 版本和已知问题
187 237
188 --- 238 ---
189 239
......
...@@ -95,9 +95,15 @@ ...@@ -95,9 +95,15 @@
95 /> 95 />
96 <span class="text-sm text-gray-500 shrink-0 ml-2 mr-5">%</span> 96 <span class="text-sm text-gray-500 shrink-0 ml-2 mr-5">%</span>
97 </div> 97 </div>
98 + </PlanPopup>
98 99
99 - <!-- Industry Picker --> 100 + <!-- Industry Picker - 提升到 PlanPopup 外部,避免嵌套弹窗导致的层级问题 -->
100 - <nut-popup position="bottom" v-model:visible="showIndustryPicker"> 101 + <nut-popup
102 + position="bottom"
103 + v-model:visible="showIndustryPicker"
104 + :z-index="9999"
105 + :overlay="true"
106 + >
101 <nut-picker 107 <nut-picker
102 :columns="industryColumns" 108 :columns="industryColumns"
103 title="选择行业" 109 title="选择行业"
...@@ -105,7 +111,6 @@ ...@@ -105,7 +111,6 @@
105 @cancel="showIndustryPicker = false" 111 @cancel="showIndustryPicker = false"
106 /> 112 />
107 </nut-popup> 113 </nut-popup>
108 - </PlanPopup>
109 </template> 114 </template>
110 115
111 <script setup> 116 <script setup>
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
9 <NavHeader title="我的计划书" /> 9 <NavHeader title="我的计划书" />
10 10
11 <!-- Search Bar --> 11 <!-- Search Bar -->
12 - <view class="px-[24rpx] py-[16rpx]"> 12 + <view class="px-[24rpx] py-[16rpx] bg-white">
13 <SearchBar 13 <SearchBar
14 v-model="searchValue" 14 v-model="searchValue"
15 placeholder="搜索计划书名称、客户姓名..." 15 placeholder="搜索计划书名称、客户姓名..."
......