218 行
5.3 KiB
Plaintext
218 行
5.3 KiB
Plaintext
<template>
|
|
<waterflow :id="id" class="grid" :bounces="false" :scroll-y="true" :custom-nested-scroll="true"
|
|
main-axis-gap="8px" cross-axis-gap="8px" cross-axis-count=2
|
|
@scrolltolower="loadData(null)" associative-container="nested-scroll-view">
|
|
<flow-item class="flow-item" v-for="(item, _) in datagrid" :key="item.plugin_id" type=1>
|
|
<view class="flow-item-icon">
|
|
<image class="flow-item-icon-image" :src="item.plugin_img_link" mode="aspectFit"></image>
|
|
</view>
|
|
<view class="flow-item-fill">
|
|
<view class="flex-row">
|
|
<text class="title">{{item.plugin_name}}</text>
|
|
</view>
|
|
<view>
|
|
<text class="description-text">{{item.plugin_intro}}</text>
|
|
</view>
|
|
<uni-rate :value="(item.score as number) / 10" :full="true" :readonly="true"></uni-rate>
|
|
<view class="tag-grid">
|
|
<text class="tag-item" v-for="(item2, index2) in (item.tags as Array<string>).slice(0,1)" :key="index2">{{item2}}</text>
|
|
</view>
|
|
<view class="flex-row update-date">
|
|
<text class="author">{{item.author_name}}</text>
|
|
</view>
|
|
<view class="flex-row update-date">
|
|
<text class="update-date-text">更新日期</text>
|
|
<text class="update-date-value">{{item.update_date}}</text>
|
|
</view>
|
|
</view>
|
|
</flow-item type="20">
|
|
<flow-item slot="load-more" class="loading" type=6>
|
|
<!-- <uni-loading :loading="loading" color="#999" :text="loadingText"></uni-loading> -->
|
|
<loading v-if="loadingRef" style="color: #999"></loading>
|
|
<text v-if="isEnded" style="color: #999">到底了</text>
|
|
</flow-item>
|
|
</waterflow>
|
|
</template>
|
|
|
|
<script setup lang="uts">
|
|
/**
|
|
* @description: 作为瀑布流内容页,支持按分类加载卡片数据并在滚动到底部后继续追加内容。
|
|
* @logic: 页面根据父级传入的分类参数请求瀑布流接口,首次显示时按需预加载,触底后继续请求下一页并更新瀑布流数据源。
|
|
* @optimization: 通过 `preload` 控制首次请求时机,避免所有标签页同时加载;瀑布流列表采用分页追加方式,降低首屏数据量和布局压力。
|
|
*/
|
|
const SERVER_URL = "https://unidemo.dcloud.net.cn/plugin/uniappx-plugin-list"
|
|
const PAGE_SIZE = 10; // 最大值 10
|
|
|
|
type flowItem = {
|
|
plugin_id : number,
|
|
plugin_img_link : string,
|
|
plugin_name : string,
|
|
plugin_intro : string,
|
|
score : number,
|
|
tags : Array<string>,
|
|
update_date : string,
|
|
author_name : string,
|
|
}
|
|
|
|
type ResponseDataType = {
|
|
code : number,
|
|
data : flowItem[]
|
|
}
|
|
|
|
const props = defineProps({
|
|
type: { type: String, default: '' },
|
|
preload: { type: Boolean, default: false },
|
|
id: { type: String, default: '' }
|
|
})
|
|
|
|
const loadingRef = ref(false);
|
|
const datagrid = ref([] as flowItem[]);
|
|
const isEnded = ref(false);
|
|
const loadingError = ref('');
|
|
const currentPage = ref(1);
|
|
|
|
const loadingText = computed(() : string => {
|
|
if (loadingRef.value) {
|
|
return "加载中..."
|
|
} else if (isEnded.value) {
|
|
return "没有更多了"
|
|
} else if (loadingError.value.length > 0) {
|
|
return loadingError.value
|
|
} else {
|
|
return ""
|
|
}
|
|
});
|
|
|
|
function loadData(loadComplete : (() => void) | null) {
|
|
if (loadingRef.value || isEnded.value) {
|
|
return
|
|
}
|
|
loadingRef.value = true
|
|
|
|
uni.request<ResponseDataType>({
|
|
url: SERVER_URL,
|
|
data: {
|
|
type: props.type,
|
|
page: currentPage.value,
|
|
page_size: PAGE_SIZE
|
|
},
|
|
success: (res) => {
|
|
const responseData = res.data
|
|
if (responseData == null) {
|
|
return
|
|
}
|
|
|
|
datagrid.value.push(...responseData.data)
|
|
|
|
if (responseData.data.length == 0) {
|
|
isEnded.value = true
|
|
} else {
|
|
currentPage.value++
|
|
}
|
|
},
|
|
fail: (err) => {
|
|
loadingError.value = err.errMsg
|
|
},
|
|
complete: () => {
|
|
loadingRef.value = false
|
|
if (loadComplete != null) {
|
|
loadComplete()
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
function refreshData(loadComplete : (() => void) | null) {
|
|
datagrid.value.length = 0
|
|
currentPage.value = 1
|
|
loadData(loadComplete)
|
|
}
|
|
|
|
onMounted(() => {
|
|
if (props.preload) {
|
|
loadData(null)
|
|
}
|
|
});
|
|
|
|
defineExpose({
|
|
refreshData,
|
|
loadData
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
.grid {
|
|
flex: 1;
|
|
background-color: #f7f7f7;
|
|
}
|
|
|
|
.flow-item {
|
|
flex-direction: column;
|
|
border-radius: 5px;
|
|
background-color: #ffffff;
|
|
}
|
|
|
|
.flow-item-icon {
|
|
position: relative;
|
|
}
|
|
|
|
.flow-item-icon-image {
|
|
width: 100%;
|
|
}
|
|
|
|
.flow-item-fill {
|
|
flex: 1;
|
|
padding: 5px;
|
|
}
|
|
|
|
.description-text {
|
|
font-size: 13px;
|
|
color: #666;
|
|
line-height: 19px;
|
|
}
|
|
|
|
.tag-grid {
|
|
flex-direction: row;
|
|
margin-top: 5px;
|
|
}
|
|
|
|
.tag-item {
|
|
font-size: 12px;
|
|
background-color: #EFF9F0;
|
|
color: #639069;
|
|
border-radius: 20px;
|
|
margin-right: 5px;
|
|
padding: 2px 5px;
|
|
}
|
|
|
|
.update-date {
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.update-date-text {
|
|
font-size: 12px;
|
|
color: #888888;
|
|
}
|
|
|
|
.update-date-value {
|
|
font-size: 12px;
|
|
color: #777777;
|
|
margin-left: 5px;
|
|
}
|
|
|
|
.author {
|
|
font-size: 12px;
|
|
color: #008000;
|
|
}
|
|
|
|
.loading {
|
|
padding: 30px;
|
|
align-items: center;
|
|
height: 80px;
|
|
}
|
|
|
|
.flex-row {
|
|
flex-direction: row;
|
|
}
|
|
</style>
|