fix(BrandModelPicker): 修复内容高度计算问题并优化滚动体验
动态计算品牌选择器内容区域高度,替代原有固定值 添加 catch-move 属性防止滚动冲突 增加底部内边距确保最后一个项目可见 添加错误处理机制和降级方案
Showing
1 changed file
with
44 additions
and
8 deletions
| ... | @@ -3,11 +3,11 @@ | ... | @@ -3,11 +3,11 @@ |
| 3 | <!-- 品牌选择弹框 --> | 3 | <!-- 品牌选择弹框 --> |
| 4 | <nut-popup v-model:visible="brandPickerVisible" position="bottom" :style="{ height: '80%' }"> | 4 | <nut-popup v-model:visible="brandPickerVisible" position="bottom" :style="{ height: '80%' }"> |
| 5 | <view class="brand-model-picker"> | 5 | <view class="brand-model-picker"> |
| 6 | - <view class="picker-header"> | 6 | + <view id="picker-header" class="picker-header"> |
| 7 | <text class="picker-title">选择品牌型号</text> | 7 | <text class="picker-title">选择品牌型号</text> |
| 8 | <nut-button size="small" type="primary" @click="closePicker">关闭</nut-button> | 8 | <nut-button size="small" type="primary" @click="closePicker">关闭</nut-button> |
| 9 | </view> | 9 | </view> |
| 10 | - <view class="search-container"> | 10 | + <view id="search-container" class="search-container"> |
| 11 | <nut-searchbar | 11 | <nut-searchbar |
| 12 | v-model="searchKeyword" | 12 | v-model="searchKeyword" |
| 13 | placeholder="搜索品牌名称" | 13 | placeholder="搜索品牌名称" |
| ... | @@ -21,6 +21,7 @@ | ... | @@ -21,6 +21,7 @@ |
| 21 | class="brand-content" | 21 | class="brand-content" |
| 22 | :scroll-y="true" | 22 | :scroll-y="true" |
| 23 | :style="{ height: contentHeight + 'rpx' }" | 23 | :style="{ height: contentHeight + 'rpx' }" |
| 24 | + :catch-move="true" | ||
| 24 | ref="brandContentRef" | 25 | ref="brandContentRef" |
| 25 | > | 26 | > |
| 26 | <view class="brand-list"> | 27 | <view class="brand-list"> |
| ... | @@ -68,8 +69,10 @@ | ... | @@ -68,8 +69,10 @@ |
| 68 | </template> | 69 | </template> |
| 69 | 70 | ||
| 70 | <script setup> | 71 | <script setup> |
| 71 | -import { ref, computed } from 'vue' | 72 | +import { ref, computed, onMounted } from 'vue' |
| 73 | +import Taro from '@tarojs/taro' | ||
| 72 | import { Right } from '@nutui/icons-vue-taro' | 74 | import { Right } from '@nutui/icons-vue-taro' |
| 75 | +import { $ } from '@tarojs/extend' | ||
| 73 | 76 | ||
| 74 | // 定义事件 | 77 | // 定义事件 |
| 75 | const emit = defineEmits(['confirm', 'cancel']) | 78 | const emit = defineEmits(['confirm', 'cancel']) |
| ... | @@ -210,11 +213,37 @@ const filteredBrands = computed(() => { | ... | @@ -210,11 +213,37 @@ const filteredBrands = computed(() => { |
| 210 | }) | 213 | }) |
| 211 | 214 | ||
| 212 | // 计算内容高度 | 215 | // 计算内容高度 |
| 213 | -const calculateContentHeight = () => { | 216 | +const calculateContentHeight = async () => { |
| 214 | - // 弹框总高度 - 头部高度 | 217 | + try { |
| 215 | - const popupHeight = 1200 // rpx | 218 | + // 获取窗口信息 |
| 216 | - const headerHeight = 120 // rpx (头部标题和按钮的高度) | 219 | + const windowInfo = Taro.getWindowInfo() |
| 217 | - contentHeight.value = popupHeight - headerHeight | 220 | + const windowHeight = windowInfo.windowHeight |
| 221 | + | ||
| 222 | + // 使用 setTimeout 确保 DOM 元素已渲染 | ||
| 223 | + setTimeout(async () => { | ||
| 224 | + try { | ||
| 225 | + // 获取弹框头部高度 | ||
| 226 | + const headerHeight = await $('.picker-header').height() || 120 | ||
| 227 | + // 获取搜索框高度 | ||
| 228 | + const searchHeight = await $('.search-container').height() || 100 | ||
| 229 | + | ||
| 230 | + // 计算可用高度:窗口高度的80% - 头部高度 - 搜索框高度 - 额外边距 | ||
| 231 | + const availableHeight = windowHeight * 0.8 - headerHeight - searchHeight - 40 | ||
| 232 | + | ||
| 233 | + // 转换为 rpx 单位 (假设设计稿宽度为750rpx) | ||
| 234 | + const factor = 750 / windowInfo.windowWidth | ||
| 235 | + contentHeight.value = Math.max(availableHeight * factor, 600) // 最小高度600rpx | ||
| 236 | + } catch (error) { | ||
| 237 | + console.warn('计算高度时出错,使用默认值:', error) | ||
| 238 | + // 降级方案:使用相对安全的默认值 | ||
| 239 | + contentHeight.value = windowHeight * 0.5 * (750 / windowInfo.windowWidth) | ||
| 240 | + } | ||
| 241 | + }, 100) | ||
| 242 | + } catch (error) { | ||
| 243 | + console.warn('获取窗口信息失败,使用固定高度:', error) | ||
| 244 | + // 完全降级方案:使用固定值 | ||
| 245 | + contentHeight.value = 800 | ||
| 246 | + } | ||
| 218 | } | 247 | } |
| 219 | 248 | ||
| 220 | // 显示品牌选择器 | 249 | // 显示品牌选择器 |
| ... | @@ -268,6 +297,12 @@ const closeAllPickers = () => { | ... | @@ -268,6 +297,12 @@ const closeAllPickers = () => { |
| 268 | currentBrandModels.value = [] | 297 | currentBrandModels.value = [] |
| 269 | } | 298 | } |
| 270 | 299 | ||
| 300 | +// 组件挂载时初始化 | ||
| 301 | +onMounted(() => { | ||
| 302 | + // 初始化高度计算 | ||
| 303 | + calculateContentHeight() | ||
| 304 | +}) | ||
| 305 | + | ||
| 271 | // 暴露方法给父组件 | 306 | // 暴露方法给父组件 |
| 272 | defineExpose({ | 307 | defineExpose({ |
| 273 | show, | 308 | show, |
| ... | @@ -358,6 +393,7 @@ defineExpose({ | ... | @@ -358,6 +393,7 @@ defineExpose({ |
| 358 | 393 | ||
| 359 | .brand-list { | 394 | .brand-list { |
| 360 | padding: 20rpx; | 395 | padding: 20rpx; |
| 396 | + padding-bottom: 60rpx; /* 增加底部内边距,确保最后一个项目完全可见 */ | ||
| 361 | 397 | ||
| 362 | .brand-item { | 398 | .brand-item { |
| 363 | display: flex; | 399 | display: flex; | ... | ... |
-
Please register or login to post a comment