Skip to content

详情页加载逻辑

说明: 以新闻、商品详情页为例。

版本说明

时间修改人备注
2025-04-23YG初始化文档

一、页面加载流程

  1. onLoad 中,打开loading动画,调用 nxhSDKLib.$init() 包裹页面逻辑
  2. 获取主题色配置 store.dispatch("getAppConfig", query)
  3. 获取详情页模版配置 nxhSDK.getData("cms_page_info", { template_type: 3 })
  4. 根据页面参数获取文章或商品ID,获取详情数据 nxhSDK.getData("cms_article_detail", { id: '' })
  5. 关闭loading动画

二、页面交互规范

  1. 详情页需要支持分享功能,自定义分享调用 onShareAppMessageonShareTimeline 方法
  2. 详情内容可滚动,需要用 <scroll-view scroll-y> 标签包裹内容
  3. 默认进入,要先展示loading动画,接口调用结束后,有数据则展示数据内容,无数据时,使用 <n-empty-data /> 组件占位。
  4. 接口请求成功或失败后,都要关闭 loading 动画
  5. 新闻详情页根据类型展示:
    • 文章类型:用富文本 <rich-text-render /> 展示
    • 图集类型:顶部展示图片轮播图,下方展示文字内容
    • 视频类型:顶部展示视频,下方展示文字内容
    • 下载类型:上方展示文字内容,下方展示下载列表
  6. 商品详情页轮播图可点击放大,购买等操作按钮固定在屏幕下方。

三、代码实现与解析

1. 打开loading动画,调用 nxhSDKLib.$init() 包裹页面逻辑

vue
<script setup>
onLoad((query) => {
    uni.showLoading({
      title: '加载中...',
      mask: true
    })
    nxhSDKLib.$init(() => {
        // 写你的页面接口调用
    })
})
</script>

2. 获取主题色配置 store.dispatch("getAppConfig", query)

调用了该代码后,会自动获取主题色,并存储在 store 中,方便其他页面调用。

vue
<script setup>
const styleJson = computed(() => store.state?.appConfig?.style)

onLoad((query) => {
    nxhSDKLib.$init(() => {
        store.dispatch("getAppConfig", query)
    })
})
</script>

3. 获取页面模版配置 nxhSDK.getData("cms_page_info", { template_type: 2 })

  • 调用SDK接口获取页面配置信息
  • 解析返回的配置数据,更新列表配置和列表类型
vue
<script setup>
const getPageInfo = () => {
  nxhSDK.getData("cms_page_info", { template_type: 3 }).then((res) => {
    const { page_config } = res?.result?.info
    if (page_config) {
        pageConfig.value = JSON.parse(page_config || '{}')
    }
  })
}
</script>

4. 获取id,调用详情接口 nxhSDK.getData("cms_article_detail", { id: query.did })

vue
<script setup>
const fetchNewsDetail = async (did) => {
    try {
        const data = await nxhSDK.getData("cms_article_detail", {id: did, show_template: 1, show_content: 1, show_attr: 1})
        const {
           id, title, title_sub, updated_at, tag_name, content, attach, attach_ext, real_template_type
        } = data.result
        newsDetailBlock.id = id;
        newsDetailBlock.title = title;
        if (tag_name) {
            newsDetailBlock.tags = tag_name.replace(//g, ',').split(',').filter(tag => tag.trim() !== '');
        } else {
            newsDetailBlock.tags = [];
        }
        newsDetailBlock.date = updated_at;
        newsDetailBlock.content = decodeURIComponent(content);
        newsDetailBlock.attach = JSON.parse(attach || '[]');
        newsDetailBlock.attach_ext = JSON.parse(attach_ext || '[]').map((i) => ({ ...i, type: 'link'}));
        newsDetailBlock.real_template_type = real_template_type;
        console.warn('fetchNewsDetail1', data, newsDetailBlock);
        
    } catch (error) {
        console.error('Error fetching news detail:', error);
    }
};
</script>

5. 关闭loading动画

vue
<script setup>
onLoad((query) => {
    nxhSDKLib.$init(() => {
        // 详情接口请求后
        uni.hideLoading();
        loading.value = false;
    })
})
</script>

四、完整代码示例

vue
<template>
    <news-detail :block="newsDetailBlock" :pageConfig="pageConfig"></news-detail>
</template>

<script setup>
import { onMounted, reactive, ref, shallowRef } from 'vue';
import {nxhSDK} from "@/nxhsdk.module.min";
import NewsDetail from '../components/NewsDetail.vue';
import { onLoad, onShareAppMessage } from '@dcloudio/uni-app';

const store = nxhSDK.useSDKStore();
const loading = ref(true);
const currentPageComponent = shallowRef(NewsDetail);
const pageConfig = ref({
    titleConfig: {
      paddingVertical: '8',
      paddingHorizontal: '0',
      fontSize: '16',
      fontWeight: 'bolder',
      color: '#2A3547',
      textAlign: 'left',
      backgroundColor: '#fff',
    },
    // 标签配置
    tagConfig: {
      tagPaddingVertical: '2',
      tagPaddingHorizontal: '8',
      tagBorderRadius: '4',
      fontSize: '12',
      fontWeight: 'normal',
      color: '#2A3547',
      tagBgColor: '#f4f4f4',
    },
    // 日期配置
    dateConfig: {
      color: '#2A3547',
      fontSize: '12',
    },
    // 分隔线配置
    dividerConfig: {
      type: 'line',
      height: '30',
      borderColor: '#EBEDF0',
      borderStyle: 'solid',
      borderMargin: '0',
    }
})

const newsDetailBlock = reactive({
    id: '',
    title: '',
    tags: [],
    date: '',
    content: '',
    attach: [], // 附件-文件
    attach_ext: [], // 附件-外链
    real_template_type: '', // 文章类型
});

const getPageInfo = () => {
  nxhSDK.getData("cms_page_info", { template_type: 3 }).then((res) => {
    console.log('getPageInfo', res)
    const { page_config } = res?.result?.info
    if (page_config) {
        pageConfig.value = JSON.parse(page_config || '{}')
    }
  })
}
const fetchNewsDetail = async (did) => {
    try {
        const data = await nxhSDK.getData("cms_article_detail", {id: did, show_template: 1, show_content: 1, show_attr: 1})
        const {
           id, title, title_sub, updated_at, tag_name, content, attach, attach_ext, real_template_type
        } = data.result
        newsDetailBlock.id = id;
        newsDetailBlock.title = title;
        if (tag_name) {
            newsDetailBlock.tags = tag_name.replace(//g, ',').split(',').filter(tag => tag.trim() !== '');
        } else {
            newsDetailBlock.tags = [];
        }
        newsDetailBlock.date = updated_at;
        newsDetailBlock.content = decodeURIComponent(content);
        newsDetailBlock.attach = JSON.parse(attach || '[]');
        newsDetailBlock.attach_ext = JSON.parse(attach_ext || '[]').map((i) => ({ ...i, type: 'link'}));
        newsDetailBlock.real_template_type = real_template_type;
        console.warn('fetchNewsDetail1', data, newsDetailBlock);
        
    } catch (error) {
        console.error('Error fetching news detail:', error);
    }
};
onShareAppMessage(() => {
    return {
        title: `${newsDetailBlock.title}`,
        path: `/news/detail/index?did=${newsDetailBlock.id}&appid=${store.state.app_id}`
    }
})
onLoad(async (query) => {
    uni.showLoading({
        title: '加载中',
    });
    const id = query.did;
    getPageInfo()
    await fetchNewsDetail(id);
    uni.hideLoading();
    loading.value = false;
});
</script>
<style scoped>

</style>