<template>
<view :class="['uni-container', { 'flex-row': isWideScreen }, isDarkMode ? 'theme-dark' : 'theme-light']" style="flex: 1;padding: 0px;">
<!-- 列表区域 :宽屏时在左侧显示,窄屏时只显示列表 -->
<list-view class="list-container" :class="{'list-narrow': isWideScreen}" refresher-enabled=true
@refresherrefresh="onRefresherrefresh" :refresher-triggered="refresherTriggered" enable-back-to-top="true">
<list-item class="banner" @click="bannerClick(banner)" type=1>
<image class="banner-img" :src="banner.cover"></image>
<text class="banner-title">{{ banner.title }}</text>
</list-item>
<sticky-section>
<sticky-header>
<view class="th-item">
<text v-for="(name,index) in th_item" :key="index" @click="clickTH(index)" class="th-item-text">
{{name}}
</text>
</view>
</sticky-header>
<list-item v-for="(value, index) in listData" :key="index" type=2>
<view class="uni-list-cell" hover-class="uni-list-cell-hover" @click="goDetail(value, index)">
<view class="uni-media-list">
<image v-if="isWideScreen" class="uni-media-list-logo" :src="value.cover"></image>
<share-element v-else :share-key="'image_'+index">
<image class="uni-media-list-logo" :src="value.cover"></image>
</share-element>
<view class="uni-media-list-body">
<text class="uni-media-list-text-top">{{ value.title }}</text>
<view class="uni-media-list-text-bottom">
<text class="uni-media-list-text">{{ value.author_name }}</text>
<text class="uni-media-list-text">{{ value.published_at }}</text>
</view>
</view>
</view>
</view>
</list-item>
</sticky-section>
</list-view>
<!-- 详情区域:宽屏时,右侧显示-->
<view v-if="isWideScreen" class="detail-container">
<detail
v-if="post_id != '' && title != '' && cover != ''"
:key="post_id"
:post_id="post_id"
:cover="cover"
:title="title"
:isWideScreen="isWideScreen"
:firstDetailContent="currentDetailContent"
/>
</view>
</view>
</template>
<script setup lang="uts">
import { state } from '@/store/index.uts'
type Banner = {
cover : string | null,
title : string | null,
post_id : string | null
}
type Item = {
author_name : string,
cover : string,
id : number,
post_id : string,
published_at : string,
title : string
}
// 导入详情组件,宽屏时,右侧直接展示详情内容
import detail from './detail/detail.uvue'
const th_item = ref(["排序", "筛选"])
const refresherTriggered = ref(false)
const banner = ref({} as Banner)
const listData = ref([] as Item[])
const last_id = ref('')
const isWideScreen = ref(false) // 是否为宽屏模式
const currentIndex = ref(0) // 当前选中的列表项索引
const post_id = ref('')
const cover = ref('')
const title = ref('')
const firstDetailContent = ref('') // 并行预加载的第一个详情内容
function checkScreenWidth() {
const deviceType = uni.getDeviceInfo().deviceType
const { windowWidth } = uni.getWindowInfo()
// 只要是pad/pc,或者宽度大于700,都算宽屏
isWideScreen.value = (
deviceType === 'pad' ||
deviceType === 'pc' ||
windowWidth > 700
)
}
function getBanner() {
let data = {
column: 'id,post_id,title,author_name,cover,published_at' //需要的字段名
};
uni.request<Banner>({
url: 'https://unidemo.dcloud.net.cn/api/banner/36kr',
data: data,
success: data => {
refresherTriggered.value = false
if (data.statusCode == 200) {
const result = data.data
if (result != null) {
banner.value = result;
}
}
},
fail: (e) => {
console.log('fail', e);
}
});
}
function goDetail(e: Item, key: number) {
currentIndex.value = key
const detail = e;
post_id.value = detail.post_id;
cover.value = detail.cover;
title.value = detail.title;
// 窄屏时跳转到详情页,宽屏时右侧直接展示
if (!isWideScreen.value) {
// #ifdef APP-ANDROID
cover.value = btoa(cover.value);
// #endif
uni.navigateTo({
url: '/pages/template/list-news/detail/detail?post_id=' + post_id.value + "&cover=" + cover.value + "&title=" + title.value + "&shareKey=image_" + key
});
}
}
function getList() {
let url = "https://unidemo.dcloud.net.cn/api/news?column=id,post_id,title,author_name,cover,published_at";
/* if (last_id.value != "") {
const minId = parseInt((last_id.value))
const time = new Date().getTime() + '';
const pageSize = 10;
url = url + "&minId=" + minId + "&time=" + time + "&pageSize=" + pageSize;
} */
uni.request<Item[]>({
url: url,
method: "GET",
success: (res) => {
if (res.statusCode == 200) {
const result = res.data
//因本接口没有更多分页数据,所以重新赋值。正常有分页的列表应该如下面push方式增加数组项
// listData.value.push(...result)
// last_id.value = listData.value[0].id + "";
if (result != null) {
listData.value = result
// 宽屏模式下,自动选中并展示第一个新闻详情
if (isWideScreen.value && listData.value.length > 0) {
goDetail(listData.value[0], 0)
// 并行预加载第一个详情内容,提升右侧展示速度
const first = listData.value[0]
uni.request({
url: 'https://unidemo.dcloud.net.cn/api/news/36kr/' + first.post_id,
success: (res) => {
if (res.statusCode == 200) {
const result = res.data as UTSJSONObject;
firstDetailContent.value = result["content"] as string
}
}
})
}
}
refresherTriggered.value = false;
}
},
fail: (res) => {
console.log('fail', res);
refresherTriggered.value = false
}
});
}
function bannerClick(e: Banner) {
const detail = e;
const post_id_val = detail.post_id;
let cover_val = detail.cover ?? "";
// #ifdef APP-ANDROID
cover_val = btoa(cover_val);
// #endif
const title_val = detail.title;
uni.navigateTo({
url: '/pages/template/list-news/detail/detail?post_id=' + post_id_val + "&cover=" + cover_val + "&title=" + title_val
});
}
function clickTH(index: number) {
uni.showModal({
content: "点击表头项:" + index,
showCancel: false
});
}
function onRefresherrefresh() {
refresherTriggered.value = true
getBanner();
getList();
}
const currentDetailContent = computed(() => {
// 只在宽屏且是第一个文章时用预加载内容
if (
isWideScreen.value &&
listData.value.length > 0 &&
post_id.value === listData.value[0].post_id &&
firstDetailContent.value !== ''
) {
return firstDetailContent.value
}
return ''
})
const isDarkMode = computed(() => state.isDarkMode)
onLoad(() => {
checkScreenWidth()
getBanner()
getList()
})
onResize(() => {
checkScreenWidth()
})
</script>
<style>
.flex-row {
flex-direction: row;
}
.list-container {
width: 100%;
background-color: var(--list-background-color,#ffffff);
/* #ifdef APP */
flex: 1;
/* #endif */
}
.list-narrow {
/* #ifdef WEB */
width: 360px;
/* #endif */
/* #ifndef WEB */
width: 100px;
/* #endif */
}
.th-item{
width: 100%;
height:44px;
background-color: var(--list-background-color,#ffffff);
flex-direction: row;
justify-content:center;
align-items:center;
}
.th-item-text{
margin-right: 20px;
color: var(--text-color,#333333);
}
.detail-container {
flex: 1;
min-width: 0;
/* 防止溢出 */
padding: 20px;
background-color: var(--background-color,#f8f8f8);
/* #ifdef WEB */
overflow: auto;
/* #endif */
}
.banner {
height: 180px;
overflow: hidden;
position: relative;
background-color: var(--background-color,#f8f8f8);
}
.banner-img {
width: 100%;
}
.banner-title {
max-height: 42px;
overflow: hidden;
position: absolute;
left: 15px;
bottom: 15px;
width: 90%;
font-size: 16px;
font-weight: 400;
line-height: 21px;
color: white;
}
.uni-media-list {
padding: 11px 15px;
box-sizing: border-box;
display: flex;
width: 100%;
flex-direction: row;
}
.uni-media-list-logo {
width: 90px;
height: 70px;
}
.uni-media-list-body {
flex: 1;
padding-left: 7px;
justify-content: space-around;
}
.uni-media-list-text-top {
/* height: 37px; */
font-size: 14px;
lines: 2;
overflow: hidden;
color: var(--text-color,#333333);
}
.uni-media-list-text-bottom {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.uni-media-list-text {
color: #9D9D9F;
font-size: 13px;
}
</style>