文件路径: E:/homework/uniappv3tswallpaper/pages/preview/preview.vue
修改了点击图片信息后,底部安全区域透明的问题。
修改了 popup
组件的标签内属性。
<template>
<view class="">
<view class="preview" @click="changeMask" v-if="currentInfo">
<swiper circular="true" :current="currentIndex" @change="swiperChange">
<swiper-item v-for="(item,index) in classList" :key="item._id">
<view class="swiper-item">
<image v-if="readImgs.includes(index)" :src="item.picurl" mode="aspectFill"></image>
</view>
</swiper-item>
</swiper>
</view>
<view class="mask" v-show="maskState">
<view class="goback" :style="{top:getStatusBarHeight() + 'px', height: getTitleBarHeight() + 'px'}"
@click="goBack">
<uni-icons type="back" size="20" color="#fff"></uni-icons>
</view>
<view class="num">
{{currentIndex + 1}} / {{classList.length}}
</view>
<view class="time">
<uni-dateformat :date="new Date()" format="hh:mm" />
</view>
<view class="date">
<uni-dateformat :date="new Date()" format="MM月dd日" />
</view>
<view class="footer" v-if="currentInfo">
<view class="box" @click="open">
<uni-icons type="info" size="28"></uni-icons>
<view class="text">
信息
</view>
</view>
<view class="box" @click="clickScore">
<uni-icons type="star" size="28"></uni-icons>
<view class="text">
{{currentInfo.score}}分
</view>
</view>
<view class="box" @click="clickDownload">
<uni-icons type="download" size="28"></uni-icons>
<view class="text">
下载
</view>
</view>
</view>
<uni-popup ref="infoPopup" type="bottom" :safe-area="false">
<view class="infoPopup">
<view class="popHead">
<view class="twoSide"> </view>
<view class="title">
壁纸信息
</view>
<view class="close twoSide" @click="clickInfoClose">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<view class="popContent">
<scroll-view scroll-y show-scrollbar="false">
<view class="content" v-if="currentInfo">
<view class="row">
<view class="label">
壁纸ID:
</view>
<view class="labelContent">
<text selectable="" class="value">{{currentInfo._id}}</text>
</view>
</view>
<view class="row">
<view class="label">
分类:
</view>
<view class="labelContent">
<text class="value">明星美女</text>
</view>
</view>
<view class="row">
<view class="label">
发布者:
</view>
<view class="labelContent">
<text class="value">{{currentInfo.nickname}}</text>
</view>
</view>
<view class="row">
<view class="label">
评分:
</view>
<view class="labelContent rateBox">
<uni-rate readonly="true" touchable="true" :value="currentInfo.score"
size="16" />
<text class="value">{{currentInfo.score}}分</text>
</view>
</view>
<view class="row">
<view class="label">
摘要:
</view>
<view class="labelContent">
<text class="value">{{currentInfo.description}}</text>
</view>
</view>
<view class="row">
<view class="label">
标签:
</view>
<view class="labelContent tabs" v-for="tab in currentInfo.tabs" :key="tab.id">
<text class="value tab">{{tab}}</text>
</view>
</view>
<view class="copyright">
建军事基地附件四哦那个佛哦放假哦计算机的佛i就哦i放到i杰佛i明尼苏达解耦i九年级哦i就欧锦好的话念佛哦你发的时间了哦ijoin的方式哦i
</view>
</view>
</scroll-view>
</view>
</view>
</uni-popup>
<uni-popup ref="scorePopup" type="center" :is-mask-click="true">
<view class="scorePopup">
<view class="popHead">
<view class="title_out">
<view class="title">
{{isScore?"已经评分啦":"壁纸信息"}}
</view>
</view>
<view class="close" @click="clickScoreClose">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<view class="popContent">
<view class="scoreStars">
<uni-rate v-model="scoreNumVal" @change="scoreStarsChange" allow-half="true"
:disabled="isScore" disabled-color="#ffca3e" />
</view>
<view class="scoreNum">
{{scoreNumVal}} 分
</view>
</view>
<view class="scoreButton">
<button class="subScore" @click="subScore" :disabled="!scoreNumVal || isScore">确认评分</button>
</view>
</view>
</uni-popup>
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue';
import {
getStatusBarHeight,
getTitleBarHeight
} from '@/utils/system.js'
import {
apiGetSetupScore,
apiWriteDownload,
apiGetDetailWall
} from '@/api/apis.js'
import {
onLoad,
onShareAppMessage,
onShareTimeline
} from '@dcloudio/uni-app'
const maskState = ref(true);
const infoPopup = ref(null);
const scorePopup = ref(null);
const scoreNumVal = ref(0);
const classList = ref([]);
const currentId = ref(null)
const currentIndex = ref(0)
const readImgs = ref([])
const currentInfo = ref(null)
const isScore = ref(false)
// 获取地址传递的参数
onLoad(async (e) => {
// console.log(e.id)
currentId.value = e.id
if (e.type == "share") {
let res = await apiGetDetailWall({
id: currentId.value
})
console.log(res)
classList.value = res.data.map(item => {
return {
...item,
picurl: item.smallPicurl.replace("_small.webp", ".jpg")
}
})
}
currentIndex.value = classList.value.findIndex(item => item._id == currentId.value)
readImgsFun()
currentInfoFunc()
})
// 修改swiper的current
const swiperChange = function(e) {
currentIndex.value = e.detail.current
readImgsFun()
currentInfoFunc()
}
//读取本地存储
let storageClassList = uni.getStorageSync("storageClassList") || []
classList.value = storageClassList.map(item => {
return {
...item,
picurl: item.smallPicurl.replace("_small.webp", ".jpg")
}
})
// console.log(classList.value)
// 打开遮罩层
const changeMask = () => {
maskState.value = !maskState.value
};
// 打开信息层
const open = () => {
infoPopup.value.open()
}
// 关闭信息层
const clickInfoClose = () => {
infoPopup.value.close()
}
// 打开评分
const clickScore = () => {
if (currentInfo.value.userScore) {
isScore.value = true
scoreNumVal.value = currentInfo.value.userScore
}
scorePopup.value.open()
}
// 关闭评分
const clickScoreClose = () => {
scorePopup.value.close()
scoreNumVal.value = 0
isScore.value = false
}
// score评分
const scoreStarsChange = (e) => {
scoreNumVal.value = e.value
}
// 点击确认提交
const subScore = async () => {
uni.showLoading({
title: "加载中..."
})
let {
classid,
_id: wallId
} = currentInfo.value
let res = await apiGetSetupScore({
classid,
wallId,
userScore: scoreNumVal.value
})
if (res.errCode == 0) {
uni.showToast({
title: '评分成功'
});
}
classList.value[currentIndex.value].userScore = scoreNumVal.value
uni.setStorageSync("storeClassList", classList.value)
// console.log(currentInfo.value)
clickScoreClose()
uni.hideLoading()
}
// 返回上一层
const goBack = () => {
uni.navigateBack({
success: () => {},
fail: (err) => {
uni.reLaunch({
url: "/pages/index/index"
})
}
});
}
// 图片预缓存
function readImgsFun() {
readImgs.value.push(
currentIndex.value <= 0 ? classList.value.length - 1 : currentIndex.value - 1,
currentIndex.value,
currentIndex.value >= classList.value.length - 1 ? 0 : currentIndex.value + 1
)
readImgs.value = [...new Set(readImgs.value)]
}
// 图片详情
function currentInfoFunc() {
currentInfo.value = classList.value[currentIndex.value]
// console.log(currentInfo.value)
}
// 点击下载
const clickDownload = async () => {
// #ifdef H5
uni.showModal({
content: "请长摁保存壁纸",
showCancel: false
});
// #endif
// #ifndef H5
try {
uni.showLoading({
title: '正在下载',
mask: true
});
let {
classid,
_id: wallId
} = currentInfo.value;
let res = await apiWriteDownload({
classid,
wallId
});
if (res.errCode != 0) {
throw res
};
uni.getImageInfo({
src: currentInfo.value.picurl,
success: (res) => {
uni.saveImageToPhotosAlbum({
filePath: res.path,
success: (res) => {
uni.showToast({
title: "保存成功,请到相册查看",
icon: "none"
})
},
fail: (err) => {
if (err.errMsg == "saveImageToPhotosAlbum:fail cancel") {
uni.showToast({
title: '保存失败,请重新点击下载',
icon: "none"
});
return;
}
uni.showModal({
title: '授权提示',
content: '需要授权保存相册',
showCancel: false,
success: res => {
if (res.confirm) {
uni.openSetting({
success: (setting) => {
// console.log(setting);
if (setting
.authSetting[
'scope.writePhotosAlbum'
]) {
uni.showToast({
title: '获取授权成功',
icon: "none"
});
} else {
uni.showToast({
title: '获取授权失败',
icon: "none"
});
}
}
})
}
}
})
},
complete: () => {
uni.hideLoading()
}
})
}
})
} catch (err) {
// console.log(err)
uni.hideLoading()
}
// #endif
}
// 分享给好友
onShareAppMessage((e) => {
return {
title: "壁纸小程序-好友",
path: "/pages/preview/preview?id=" + currentInfo.value._id + "&type=share"
}
})
// 分享到朋友圈
// onShareTimeline(() => {
// return {
// title: "壁纸小程序-朋友圈",
// query: "id=" + currentInfo.value._id + "&type=share"
// }
// })
</script>
<style lang="scss" scoped>
.preview {
width: 100%;
height: 100vh;
swiper {
width: 100%;
height: 100%;
.swiper-item {
height: 100%;
width: 100%;
image {
height: 100%;
width: 100%;
}
}
}
}
.mask {
&>view {
position: absolute;
left: 0%;
right: 0%;
margin: auto;
width: fit-content;
color: #fff;
}
.goback {
width: 79rpx;
height: 79rpx;
background: rgba(0, 0, 0, 0.5);
left: 30rpx;
margin-left: 0;
border-radius: 100px;
top: 0;
backdrop-filter: blur(10rpx);
border: 1rpx solid rbga(255, 255, 255, 0.3);
display: flex;
align-items: center;
justify-content: center;
}
// position: relative; // 需要的是相对于整个屏幕的绝对位置,所以在这里不设置这个属性
.num {
top: 10vh;
background: rgba(0, 0, 0, 0.3);
backdrop-filter: blur(10rpx);
padding: 8rpx 18rpx;
border-radius: 40rpx;
font-size: 28rpx;
}
.time {
top: calc(10vh + 160rpx);
font-size: 140rpx;
font-weight: 100;
line-height: 1rem;
text-shadow: 0 4rpx rgba(0, 0, 0, 0.3);
}
.date {
top: calc(10vh + 280rpx);
font-size: 34rpx;
text-shadow: 0 4rpx rgba(0, 0, 0, 0.3);
}
.footer {
bottom: 10vh;
background: rgba(255, 255, 255, 0.8);
width: 65vw;
height: 120rpx;
border-radius: 120rpx;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: space-evenly;
align-items: center;
.box {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
align-content: center;
justify-content: center;
align-items: center;
padding: 2rpx 12rpx;
.text {
color: $text-font-color-2;
font-size: 26rpx;
}
}
}
.infoPopup {
background: #fff;
padding: 30rpx;
border-radius: 30rpx 30rpx 0 0;
overflow: hidden;
color: black;
.popHead {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: space-between;
align-items: center;
.title {
color: $text-font-color-2;
font-size: 26rpx;
}
.close {
// padding: 6rpx;
}
}
.popContent {
height: 60vh;
scroll-view {
height: 100%;
.content {
.row {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
align-items: center;
justify-content: center;
padding: 16rpx 0;
font-size: 32rpx;
line-height: 1.7rem;
.label {
width: 25%;
text-align: right;
color: $text-font-color-3;
font-size: 30rpx;
}
.labelContent {
flex: 1;
width: 0;
}
.rateBox {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: flex-start;
align-items: center;
.value {
font-size: 26rpx;
color: $text-font-color-3 ;
padding-left: 25rpx;
}
}
.tabs {
display: flex;
flex-wrap: wrap;
.tab {
border: 1px solid $brand-theme-color;
color: $brand-theme-color;
font-size: 22rpx;
padding: 10rpx 30rpx;
border-radius: 40rpx;
line-height: 1rem;
margin: 0 10rpx 10rpx 0;
width: fit-content;
}
}
}
.copyright {
font-size: 22rpx;
padding: 20rpx;
background: #f6f6f6;
color: #666;
border-radius: 10rpx;
margin: 20rpx 0;
line-height: 1.6rem;
width: 100%;
}
}
}
}
}
.scorePopup {
width: 70vw;
height: 25vh;
background-color: #fff;
padding: 30rpx;
border-radius: 30rpx;
.popHead {
display: flex;
flex-wrap: wrap;
flex-direction: row-reverse;
.title_out {
width: 100%;
height: 0;
.title {
color: $text-font-color-2;
font-size: 26rpx;
text-align: center;
}
}
.close {
padding: 0 6rpx;
}
}
.popContent {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: space-evenly;
align-items: center;
padding-top: 70rpx;
.scoreNum {
text-align: right;
width: 100rpx;
color: #feca43;
}
}
.scoreButton {
padding: 80rpx 70rpx 0 70rpx;
}
}
}
</style>
文件路径: E:/homework/uniappv3tswallpaper/pages/classlist/classlist.vue
添加了 onUnload
生命周期,在离开 classlist
页面时清除缓存。
<template>
<view class="classlist">
<view class="loadingLayout" v-if="!classList.length && !noData">
<uni-load-more status="loading"></uni-load-more>
</view>
<view class="content">
<navigator :url="'/pages/preview/preview?id='+item._id" class="item" v-for="item in classList"
:key="item._id">
<image :src="item.smallPicurl" mode="aspectFill"></image>
</navigator>
</view>
<view class="loadingLayout" v-if="classList.length || noData">
<uni-load-more :status="noData? 'nomre':'loading'"></uni-load-more>
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue'
import {
apiGetCLassList
} from '@/api/apis.js'
import {
onLoad,
onUnload,
onReachBottom,
onShareAppMessage,
onShareTimeline
} from '@dcloudio/uni-app'
const queryParams = {
pageNum: 1,
pageSize: 12
}
const noData = ref(false)
onLoad(e => {
// console.log(e)
let {
id = null,
name = null
} = e
uni.setNavigationBarTitle({
title: name
})
queryParams.classid = id
queryParams.name = name
getClassList()
})
// 触底获取新数据
onReachBottom(() => {
if (noData.value) {
return
}
queryParams.pageNum++
getClassList()
})
// 定义列表参数
const classList = ref([])
// 发请求获取数据
const getClassList = async () => {
let res = await apiGetCLassList(queryParams)
classList.value = [...classList.value, ...res.data]
uni.setStorageSync("storageClassList", classList.value)
if (queryParams.pageSize > res.data.length) {
noData.value = true
}
}
// 分享给好友
onShareAppMessage((e) => {
return {
title: "壁纸小程序-好友" + queryParams.name,
path: "/pages/classlist/classlist?id=" + queryParams.classid + "&name=" + queryParams.name
}
})
// 分享到朋友圈
onShareTimeline(() => {
return {
title: "壁纸小程序-朋友圈" + queryParams.name,
query: "id=" + queryParams.classid + "&name=" + queryParams.name
}
})
// 离开页面
onUnload(() => {
uni.removeStorageSync("storageClassList")
})
</script>
<style lang="scss">
.classlist {
.content {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 5px;
padding: 5rpx;
.item {
height: 440rpx;
width: 100%;
image {
height: 100%;
width: 100%;
display: block;
}
}
}
}
</style>
文件路径: E:/homework/uniappv3tswallpaper/pages/index/index.vue
给每日推荐补全了进入 preview
页面的功能。
<template>
<view class="homeLayout pageBg">
<custom-nav-bar title="推荐"></custom-nav-bar>
<view class="banner">
<swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" circular="true"
indicator-color="rgba(255,255,255,0.5)" indicator-active-color="rgba(255,255,255,1)">
<swiper-item v-for="item in bannerList" :key="item._id">
<image :src="item.picurl" mode="scaleToFill"></image>
</swiper-item>
</swiper>
</view>
<view class="notice">
<view class="left">
<uni-icons type="sound-filled" size="20"></uni-icons>
<text class="text">公告</text>
</view>
<view class="center">
<swiper :autoplay="true" :interval="3000" :duration="1000" circular vertical>
<swiper-item v-for="item in noticeList" :key="item._id">
<navigator url="/pages/notice/detail">
{{item.title}}
</navigator>
</swiper-item>
</swiper>
</view>
<view class="right">
<uni-icons type="forward" size="16" color="#333"></uni-icons>
</view>
</view>
<view class="select">
<common-title>
<template #name>
每日推荐
</template>
<template #custom>
<view class="date">
<uni-icons type="calendar"></uni-icons>
<view class="text">
<uni-dateformat :date="Date.now()" format="dd号" />
</view>
</view>
</template>
</common-title>
<view class="content">
<scroll-view scroll-x="true">
<view class="box" v-for="item in randomList" :key="item._id" @click="goPreview(item._id)">
<image :src="item.smallPicurl" mode="aspectFill"></image>
</view>
</scroll-view>
</view>
</view>
<view class="theme">
<common-title>
<template #name>
专题精选
</template>
<template #custom>
<navigator url="">More+</navigator>
</template>
</common-title>
<view class="content">
<theme-item v-for="item in classifyList" :key="item._id" :items="item"></theme-item>
<theme-item :isMore="true"></theme-item>
</view>
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue';
import {
apiGetBanner,
apiGetDayRandom,
apiGetRequest,
apiGetClassify
} from "@/api/apis.js"
import {
onShareAppMessage,
onShareTimeline
} from "@dcloudio/uni-app"
const bannerList = ref([]);
const randomList = ref([])
const noticeList = ref([])
const classifyList = ref([])
const getBanner = async () => {
let res = await apiGetBanner()
bannerList.value = res.data
};
const getDayRandom = async () => {
let res = await apiGetDayRandom()
randomList.value = res.data
};
const getNotice = async () => {
let res = await apiGetRequest({
select: true
})
noticeList.value = res.data
}
const getClassify = async () => {
let res = await apiGetClassify({
select: true
})
classifyList.value = res.data
}
// 点击跳转到壁纸预览页面
const goPreview = (id) => {
uni.setStorageSync("storageClassList", randomList.value);
uni.navigateTo({
url: '/pages/preview/preview?id=' + id
})
};
// 分享给好友
onShareAppMessage((e) => {
return {
title: "壁纸小程序好友",
path: "/pages/classify/classify"
}
})
// 分享到朋友圈
onShareTimeline(() => {
return {
title: "壁纸小程序朋友圈"
}
})
getBanner()
getDayRandom()
getNotice()
getClassify()
</script>
<style lang="scss">
.homeLayout {
.banner {
width: 750rpx;
padding: 30rpx 0;
swiper {
width: 100%;
height: 340rpx;
&-item {
width: 100%;
height: 100%;
padding: 0 30rpx;
image {
width: 100%;
height: 100%;
border-radius: 10rpx;
}
}
}
}
.notice {
margin: 0 30rpx;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: center;
align-items: center;
background: gray;
border-radius: 80rpx;
height: 80rpx;
line-height: 80rpx;
.left {
width: 140rpx;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: center;
align-items: center;
:deep() {
.uni-icons {
color: $brand-theme-color !important;
}
}
.text {
color: $brand-theme-color;
font-weight: 600;
font-size: 28rpx;
}
}
.center {
flex: 1;
height: 100%;
swiper {
height: 100%;
&-item {
// 以下三条是实现 文字长度超过显示宽度时展示省略号 的关键操作
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
// 以上三条
height: 100%;
color: $text-font-color-3;
font-size: 30rpx;
// flex布局与 text-overflow: ellipsis;属性 冲突
// display: flex;
// flex-direction: row;
// flex-wrap: nowrap;
// align-content: center;
// align-items: center;
// justify-content: flex-start;
align-content: end;
align-items: end;
}
}
}
.right {
width: 70rpx;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
align-items: center;
justify-content: center;
}
}
.select {
padding: 50rpx 30rpx 0 30rpx;
scroll-view {
white-space: nowrap;
.box {
display: inline-block;
width: 200rpx;
height: 430rpx;
margin-right: 15rpx;
image {
height: 100%;
width: 100%;
}
}
:last-child {
margin-right: 0;
border-radius: 10rpx;
}
}
.date {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: center;
align-items: center;
color: $brand-theme-color;
:deep() {
.uni-icons {
color: $brand-theme-color !important;
}
}
}
}
.theme {
padding: 50rpx 30rpx;
.content {
display: grid;
gap: 15rpx;
grid-template-columns: repeat(3, 1fr);
}
}
}
</style>