refactor(community): 重构动态详情页布局

main
cr 2026-04-26 10:54:39 +08:00
parent 856b7224c1
commit 203fd7a1a6
1 changed files with 40 additions and 77 deletions

View File

@ -5,41 +5,41 @@
<!-- 渐变背景 --> <!-- 渐变背景 -->
<view class="gradient-bg"></view> <view class="gradient-bg"></view>
<!-- 固定头部区域标题+发布信息 --> <!-- 头部区域标题+发布信息-->
<view class="detail-header" :style="{ top: navbarHeight + 'px' }"> <view class="detail-header">
<view class="header-inner"> <view class="header-inner">
<!-- 标题 --> <!-- 标题 -->
<view class="detail-title"> <view class="detail-title">
<text class="title-text">{{ detailInfo.title }}</text> <text class="title-text">{{ detailInfo.title }}</text>
</view> </view>
<!-- 发布信息 --> <!-- 发布信息 -->
<view class="publish-info"> <view class="publish-info">
<text class="community-name">{{ detailInfo.communityName }}</text> <text class="community-name">{{ detailInfo.communityName }}</text>
<text class="publish-date">{{ detailInfo.publishDate ? sheep.$helper.timeFormat(detailInfo.publishDate, 'yyyy年mm月dd日 hh:MM') : '' }}</text> <text class="publish-date">{{ detailInfo.publishDate ? sheep.$helper.timeFormat(detailInfo.publishDate, 'yyyy年mm月dd日 hh:MM') : '' }}</text>
</view> </view>
<!-- 分割线 --> <!-- 分割线 -->
<view class="divider"></view> <view class="divider"></view>
</view>
</view>
<!-- 富文本内容 - 固定滚动区域 -->
<scroll-view class="content-scroll" scroll-y :style="{ height: scrollHeight + 'px', top: scrollTop + 'px' }">
<view class="content-card">
<view class="content-inner">
<mp-html :content="detailInfo.content"></mp-html>
</view> </view>
</view> </view>
<!-- 底部占位 -->
<view class="bottom-placeholder"></view> <!-- 富文本内容 - calc 计算高度滚动区域 -->
</scroll-view> <scroll-view class="content-scroll" scroll-y>
<view class="content-card">
<view class="content-inner">
<mp-html :content="detailInfo.content+detailInfo.content"></mp-html>
</view>
</view>
<!-- 底部占位 -->
<view class="bottom-placeholder"></view>
</scroll-view>
</view> </view>
</s-layout> </s-layout>
</template> </template>
<script setup> <script setup>
import { ref, onMounted, nextTick, getCurrentInstance } from 'vue'; import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app'; import { onLoad } from '@dcloudio/uni-app';
import DynamicsApi from '@/sheep/api/community/dynamics'; import DynamicsApi from '@/sheep/api/community/dynamics';
import sheep from '@/sheep'; import sheep from '@/sheep';
@ -52,14 +52,6 @@ const detailInfo = ref({
content: '', content: '',
}); });
//
const scrollHeight = ref(0);
//
const scrollTop = ref(0);
// px
const navbarHeight = sheep.$platform.navbar;
// //
onLoad((options) => { onLoad((options) => {
if (options.id) { if (options.id) {
@ -67,31 +59,6 @@ onLoad((options) => {
} }
}); });
// scroll-view
const calcScrollHeight = () => {
const instance = getCurrentInstance();
nextTick(() => {
const sysInfo = uni.getSystemInfoSync();
const query = uni.createSelectorQuery().in(instance);
//
query.select('.detail-header').boundingClientRect();
query.exec((res) => {
const headerRect = res[0];
if (headerRect) {
const safeBottom = sysInfo.safeAreaInsets?.bottom || 0;
// scroll-view = + headerRect.topfixed
scrollTop.value = navbarHeight + headerRect.height;
scrollHeight.value = sysInfo.windowHeight - scrollTop.value - safeBottom;
}
});
});
};
onMounted(() => {
calcScrollHeight();
});
// //
async function loadDetail(id) { async function loadDetail(id) {
const { code, data } = await DynamicsApi.getDetail(id); const { code, data } = await DynamicsApi.getDetail(id);
@ -104,20 +71,18 @@ async function loadDetail(id) {
publishDate: data.publishTime || '', publishDate: data.publishTime || '',
content: data.content || '', content: data.content || '',
}; };
// Vue DOM
nextTick(() => {
calcScrollHeight();
});
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
/* 页面容器 */ /* 页面容器:纵向 flex 布局,减去导航栏高度 176rpx */
.detail-page { .detail-page {
position: relative; position: relative;
z-index: 1; display: flex;
flex-direction: column;
height: calc(100vh - 176rpx);
overflow: hidden;
} }
/* 渐变背景 */ /* 渐变背景 */
@ -132,13 +97,11 @@ async function loadDetail(id) {
pointer-events: none; pointer-events: none;
} }
/* 固定头部区域 */ /* 头部区域:正常文档流,不参与滚动 */
.detail-header { .detail-header {
position: fixed; position: relative;
left: 0;
width: 100%;
z-index: 10; z-index: 10;
background: transparent; flex-shrink: 0;
} }
.header-inner { .header-inner {
@ -187,12 +150,12 @@ async function loadDetail(id) {
margin-bottom: 32rpx; margin-bottom: 32rpx;
} }
/* 内容滚动区域 - 固定定位 */ /* 内容滚动区域flex:1 占满头部剩余空间height:0 是小程序 scroll-view 配合 flex 的关键 */
.content-scroll { .content-scroll {
position: fixed; position: relative;
left: 0;
width: 100%;
z-index: 5; z-index: 5;
flex: 1;
height: 0;
} }
/* 内容卡片 */ /* 内容卡片 */
@ -218,8 +181,8 @@ async function loadDetail(id) {
} }
} }
/* 底部占位 */ /* 底部占位40rpx 基础间距 + 安全区域 */
.bottom-placeholder { .bottom-placeholder {
height: 40rpx; height: calc(40rpx + env(safe-area-inset-bottom));
} }
</style> </style>