27.首次加载额外的图片网络消耗
Array.prototype.includes() - JavaScript | MDN
<script setup>
import {
ref
} from 'vue';
import {
onLoad
} from "@dcloudio/uni-app"
import {
getStatusBarHeight
} from "../../utils/system.js"
const maskState = ref(true);
// 弹窗状态
const infoPopup = ref(null);
const scorePopup = ref(null);
const userScore = ref(0)
const classList = ref([]);
// 当前的ID
const currentId = ref(null);
const currentIndex = ref(0)
// 数组存储浏览过的壁纸
const readImgs = ref([]);
//点击info弹窗
const clickInfo = () => {
infoPopup.value.open();
}
//点击关闭信息弹窗
const clickInfoClose = () => {
infoPopup.value.close();
}
//评分弹窗
const clickScore = () => {
scorePopup.value.open();
}
//关闭评分框
const clickScoreClose = () => {
scorePopup.value.close();
}
//确认评分
const submitScore = async () => {
console.log("评分成功");
}
//遮罩层状态
const maskChange = () => {
maskState.value = !maskState.value
}
//返回上一页
const goBack = () => {
uni.navigateBack()
}
//获取缓存
const storgClassList = uni.getStorageSync("storgClassList") || [];
classList.value = storgClassList.map(item => {
return {
...item,
picurl: item.smallPicurl.replace("_small.webp", ".jpg")
}
})
onLoad(async (e) => {
// 赋值
currentId.value = e.id;
// findIndex比较每一个_id与传入的id相等
currentIndex.value = classList.value.findIndex(item => item._id == currentId.value)
// 把浏览过的壁纸索引推入
readImgsFun();
})
const swiperChange = (e) => {
// 赋值索引值
currentIndex.value = e.detail.current;
// 把滑动过的壁纸索引推入
readImgsFun();
console.log(e);
}
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)];
}
</script>
<template>
<view class="preview">
<!-- 轮播图 -->
<swiper circular :current="currentIndex" @change="swiperChange">
<swiper-item v-for="item in classList" :key="item._id">
<image v-if="readImgs.includes(index)" @click="maskChange" :src="item.picurl" mode="aspectFill"></image>
</swiper-item>
</swiper>
<!-- 遮罩层 -->
<view class="mask" v-if="maskState">
<!-- 返回按钮 -->
<!-- #ifndef MP-TOUTIAO -->
<view class="goBack" @click="goBack" :style="{top:getStatusBarHeight()+'px'}">
<uni-icons type="back" color="#fff" size="20"></uni-icons>
</view>
<!-- #endif -->
<!-- 显示进度 动态数据-->
<view class="count">{{currentIndex+1}}/ {{classList.length}}</view>
<!-- 时间-->
<view class="time">
<uni-dateformat :date="new Date()" format="hh:mm"></uni-dateformat>
</view>
<!-- 日期 -->
<view class="date">
<uni-dateformat :date="new Date()" format="MM月dd日"></uni-dateformat>
</view>
<!-- 按钮 -->
<view class="footer">
<view class="box" @click="clickInfo">
<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">5分</view>
</view>
<view class="box">
<uni-icons type="download" size="23"></uni-icons>
<view class="text">下载</view>
</view>
</view>
</view>
<uni-popup ref="infoPopup" type="bottom">
<view class="infoPopup">
<!-- 标题 退出x -->
<view class="popHeader">
<view></view>
<view class="title">壁纸信息</view>
<view class="close" @click="clickInfoClose">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<!-- 滚动条 -->
<scroll-view scroll-y>
<view class="content">
<view class="row">
<view class="label">壁纸ID:</view>
<text selectable class="value">123456</text>
</view>
<view class="row">
<view class="label">分类:</view>
<text class="value class">明星美女</text>
</view>
<view class="row">
<view class="label">发布者:</view>
<text class="value">abc</text>
</view>
<view class="row">
<text class="label">评分:</text>
<view class='value roteBox'>
<uni-rate readonly touchable value="4" size="16" />
<text class="score">5分</text>
</view>
</view>
<view class="row">
<text class="label">摘要:</text>
<view class='value'>
XXXXX
</view>
</view>
<view class="row">
<text class="label">标签:</text>
<view class='value tabs'>
<view class="tab" v-for="tab in 3">
1
</view>
</view>
</view>
<view class="copyright">声明:XXXXXXXXXXX</view>
</view>
</scroll-view>
</view>
</uni-popup>
<uni-popup ref="scorePopup" :is-mask-click="false">
<view class="scorePopup">
<view class="popHeader">
<view></view>
<view class="title">壁纸评分</view>
<view class="close" @click="clickScoreClose()">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<!-- 内容 -->
<view class="content">
<uni-rate v-model="userScore" allowHalf disabled-color="#FFCA3E" />
<text class="text">{{userScore}}分</text>
</view>
<!-- 按钮 -->
<view class="footer">
<button @click="submitScore" :disabled="!userScore " type="default" size="mini" plain>确认评分</button>
</view>
</view>
</uni-popup>
</view>
</template>
<style lang="scss" scoped>
.preview {
width: 100%;
height: 100vh;
position: relative;
swiper {
width: 100%;
height: 100%;
image {
width: 100%;
height: 100%;
}
}
// 信息
.mask {
&>view {
//让mask紧邻的view
position: absolute;
left: 0;
margin: auto;
color: #fff;
right: 0;
width: fit-content; //内容决定宽度
}
.goBack {
width: 38px;
height: 38px;
background: rgba(0, 0, 0, 0.5);
left: 30rpx;
margin-left: 0;
border-radius: 100px;
top: 0;
backdrop-filter: blur(10rpx);
border: 1rpx solid rgba(255, 255, 255, 0.3);
// 图标居中
display: flex;
align-items: center;
justify-content: center;
}
.count {
top: 10vh;
background: rgba(0, 0, 0, 0.3); //背景
font-size: 28rpx; //字号
border-radius: 40rpx; //圆角
padding: 8rpx 28rpx; //上下8 左右28
backdrop-filter: blur(10rpx); //模糊
}
.time {
font-size: 140rpx; //字体大小
top: calc(10vh + 80rpx); //计算函数
font-weight: 100; //字体加粗
line-height: 1em; //行高
text-shadow: 0 4rpx rgba(0, 0, 0, 0.3); //文字阴影
}
.date {
font-size: 34rpx;
top: calc(10vh + 230rpx);
text-shadow: 0 2rpx rgba(0, 0, 0, 0.3);
}
.footer {
background: rgba(255, 255, 255, 0.8);
bottom: 10vh; //以底为基准
width: 65vw;
height: 120rpx;
border-radius: 120rpx; //圆角
color: #000;
display: flex; //一行
justify-content: space-around; //两端对齐
align-items: center;
box-shadow: 0 2rpx 0 rgba(0, 0, 0, 0.1); //阴影
backdrop-filter: blur(20rpx); //模糊
.box {
display: flex;
flex-direction: column; //文本行排列顺序、堆叠的方向
align-items: center;
justify-content: center;
padding: 2rpx 12rpx;
.text {
font-size: 26rpx;
color: $text-font-color-2;
}
}
}
}
// 标题 退出x
.popHeader {
display: flex;
justify-content: space-between; //两端对齐
align-items: center;
.title {
color: $text-font-color-2;
font-size: 26rpx;
}
.close {
padding: 6rpx;
}
}
.infoPopup {
background: #fff;
padding: 30rpx;
border-radius: 30rpx 30rpx 0 0; //左右圆角
overflow: hidden; //超出隐藏
scroll-view {
max-height: 60vh; //最大高度
.content {
// 壁纸id
.row {
display: flex;
padding: 16rpx 0;
font-size: 32rpx;
line-height: 1.7em; //行间距
// 文字(不可选中
.label {
color: $text-font-color-3;
width: 140rpx;
text-align: right;
font-size: 30rpx;
}
// 数据(可选
.value {
flex: 1;
width: 0;
}
.roteBox {
display: flex; //显示一行
align-items: center; //垂直居中
//文字分数
.score {
font-size: 26rpx;
color: $text-font-color-2;
padding-left: 10rpx;
}
}
// 标签组
.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: 1em;
margin: 0 10rpx 10rpx 0;
}
}
.class {
color: $brand-theme-color;
}
}
.copyright {
font-size: 28rpx;
padding: 20rpx;
background: #F6F6F6;
color: #666;
border-radius: 10rpx;
margin: 20rpx 0;
line-height: 1.6em;
}
}
}
}
.scorePopup {
background: #fff;
padding: 30rpx;
width: 70vw;
border-radius: 30rpx; //圆角
// 内容
.content {
padding: 30rpx 0;
display: flex; //居中
justify-content: center;
align-items: center;
.text {
color: #FFCA3E;
padding-left: 10rpx;
width: 80rpx;
line-height: 1em;
text-align: right; //右对齐
font-size: 28rpx;
}
}
.footer {
padding: 10rpx 0;
display: flex;
align-items: center;
justify-content: center;
}
}
}
</style>
28.展示每张壁纸的专属信息
<script setup>
import {
ref
} from 'vue';
import {
onLoad
} from "@dcloudio/uni-app"
import {
getStatusBarHeight
} from "../../utils/system.js"
const maskState = ref(true);
// 弹窗状态
const infoPopup = ref(null);
const scorePopup = ref(null);
const userScore = ref(0)
const classList = ref([]);
// 当前的ID
const currentId = ref(null);
const currentIndex = ref(0)
// 壁纸信息
const currentInfo = ref(null);
// 数组存储浏览过的壁纸
const readImgs = ref([]);
//点击info弹窗
const clickInfo = () => {
infoPopup.value.open();
}
//点击关闭信息弹窗
const clickInfoClose = () => {
infoPopup.value.close();
}
//评分弹窗
const clickScore = () => {
scorePopup.value.open();
}
//关闭评分框
const clickScoreClose = () => {
scorePopup.value.close();
}
//确认评分
const submitScore = async () => {
console.log("评分成功");
}
//遮罩层状态
const maskChange = () => {
maskState.value = !maskState.value
}
//返回上一页
const goBack = () => {
uni.navigateBack()
}
//获取缓存
const storgClassList = uni.getStorageSync("storgClassList") || [];
classList.value = storgClassList.map(item => {
return {
...item,
picurl: item.smallPicurl.replace("_small.webp", ".jpg")
}
})
onLoad(async (e) => {
// 赋值
currentId.value = e.id;
// findIndex比较每一个_id与传入的id相等
currentIndex.value = classList.value.findIndex(item => item._id == currentId.value)
//赋值 壁纸信息,根据索引值
currentInfo.value = classList.value[currentIndex.value]
// 把浏览过的壁纸索引推入
readImgsFun();
})
const swiperChange = (e) => {
// 赋值索引值
currentIndex.value = e.detail.current;
//赋值 壁纸信息,根据索引值
currentInfo.value = classList.value[currentIndex.value]
// 把滑动过的壁纸索引推入
readImgsFun();
console.log(e);
}
console.log(classList.value);
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)];
}
</script>
<template>
<view class="preview">
<!-- 轮播图 -->
<swiper circular :current="currentIndex" @change="swiperChange">
<swiper-item v-for="(item,index) in classList" :key="item._id">
<image v-if="readImgs.includes(index)" @click="maskChange" :src="item.picurl" mode="aspectFill"></image>
</swiper-item>
</swiper>
<!-- 遮罩层 -->
<view class="mask" v-if="maskState">
<!-- 返回按钮 -->
<!-- #ifndef MP-TOUTIAO -->
<view class="goBack" @click="goBack" :style="{top:getStatusBarHeight()+'px'}">
<uni-icons type="back" color="#fff" size="20"></uni-icons>
</view>
<!-- #endif -->
<!-- 显示进度 动态数据-->
<view class="count">{{currentIndex+1}} / {{classList.length}}</view>
<!-- 时间-->
<view class="time">
<uni-dateformat :date="new Date()" format="hh:mm"></uni-dateformat>
</view>
<!-- 日期 -->
<view class="date">
<uni-dateformat :date="new Date()" format="MM月dd日"></uni-dateformat>
</view>
<!-- 按钮 -->
<view class="footer">
<view class="box" @click="clickInfo">
<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">5分</view>
</view>
<view class="box">
<uni-icons type="download" size="23"></uni-icons>
<view class="text">下载</view>
</view>
</view>
</view>
<uni-popup ref="infoPopup" type="bottom">
<view class="infoPopup">
<!-- 标题 退出x -->
<view class="popHeader">
<view></view>
<view class="title">壁纸信息</view>
<view class="close" @click="clickInfoClose">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<!-- 滚动条 -->
<scroll-view scroll-y>
<view class="content">
<view class="row">
<view class="label">壁纸ID:</view>
<text selectable class="value">{{currentInfo._id}}</text>
</view>
<!-- <view class="row">
<view class="label">分类:</view>
<text class="value class">明星美女</text>
</view> -->
<view class="row">
<view class="label">发布者:</view>
<text class="value">{{currentInfo.nickname}}</text>
</view>
<view class="row">
<text class="label">评分:</text>
<view class='value roteBox'>
<uni-rate readonly touchable value="4" size="16" />
<text class="score">{{currentInfo.score}}分</text>
</view>
</view>
<view class="row">
<text class="label">摘要:</text>
<view class='value'>
{{currentInfo.description}}
</view>
</view>
<view class="row">
<text class="label">标签:</text>
<view class='value tabs'>
<view class="tab" v-for="tab in currentInfo.tabs">
{{tab}}
</view>
</view>
</view>
<view class="copyright">声明:XXXXXXXXXXX</view>
</view>
</scroll-view>
</view>
</uni-popup>
<uni-popup ref="scorePopup" :is-mask-click="false">
<view class="scorePopup">
<view class="popHeader">
<view></view>
<view class="title">壁纸评分</view>
<view class="close" @click="clickScoreClose()">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<!-- 内容 -->
<view class="content">
<uni-rate v-model="userScore" allowHalf disabled-color="#FFCA3E" />
<text class="text">{{userScore}}分</text>
</view>
<!-- 按钮 -->
<view class="footer">
<button @click="submitScore" :disabled="!userScore " type="default" size="mini" plain>确认评分</button>
</view>
</view>
</uni-popup>
</view>
</template>
<style lang="scss" scoped>
.preview {
width: 100%;
height: 100vh;
position: relative;
swiper {
width: 100%;
height: 100%;
image {
width: 100%;
height: 100%;
}
}
// 信息
.mask {
&>view {
//让mask紧邻的view
position: absolute;
left: 0;
margin: auto;
color: #fff;
right: 0;
width: fit-content; //内容决定宽度
}
.goBack {
width: 38px;
height: 38px;
background: rgba(0, 0, 0, 0.5);
left: 30rpx;
margin-left: 0;
border-radius: 100px;
top: 0;
backdrop-filter: blur(10rpx);
border: 1rpx solid rgba(255, 255, 255, 0.3);
// 图标居中
display: flex;
align-items: center;
justify-content: center;
}
.count {
top: 10vh;
background: rgba(0, 0, 0, 0.3); //背景
font-size: 28rpx; //字号
border-radius: 40rpx; //圆角
padding: 8rpx 28rpx; //上下8 左右28
backdrop-filter: blur(10rpx); //模糊
}
.time {
font-size: 140rpx; //字体大小
top: calc(10vh + 80rpx); //计算函数
font-weight: 100; //字体加粗
line-height: 1em; //行高
text-shadow: 0 4rpx rgba(0, 0, 0, 0.3); //文字阴影
}
.date {
font-size: 34rpx;
top: calc(10vh + 230rpx);
text-shadow: 0 2rpx rgba(0, 0, 0, 0.3);
}
.footer {
background: rgba(255, 255, 255, 0.8);
bottom: 10vh; //以底为基准
width: 65vw;
height: 120rpx;
border-radius: 120rpx; //圆角
color: #000;
display: flex; //一行
justify-content: space-around; //两端对齐
align-items: center;
box-shadow: 0 2rpx 0 rgba(0, 0, 0, 0.1); //阴影
backdrop-filter: blur(20rpx); //模糊
.box {
display: flex;
flex-direction: column; //文本行排列顺序、堆叠的方向
align-items: center;
justify-content: center;
padding: 2rpx 12rpx;
.text {
font-size: 26rpx;
color: $text-font-color-2;
}
}
}
}
// 标题 退出x
.popHeader {
display: flex;
justify-content: space-between; //两端对齐
align-items: center;
.title {
color: $text-font-color-2;
font-size: 26rpx;
}
.close {
padding: 6rpx;
}
}
.infoPopup {
background: #fff;
padding: 30rpx;
border-radius: 30rpx 30rpx 0 0; //左右圆角
overflow: hidden; //超出隐藏
scroll-view {
max-height: 60vh; //最大高度
.content {
// 壁纸id
.row {
display: flex;
padding: 16rpx 0;
font-size: 32rpx;
line-height: 1.7em; //行间距
// 文字(不可选中
.label {
color: $text-font-color-3;
width: 140rpx;
text-align: right;
font-size: 30rpx;
}
// 数据(可选
.value {
flex: 1;
width: 0;
}
.roteBox {
display: flex; //显示一行
align-items: center; //垂直居中
//文字分数
.score {
font-size: 26rpx;
color: $text-font-color-2;
padding-left: 10rpx;
}
}
// 标签组
.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: 1em;
margin: 0 10rpx 10rpx 0;
}
}
.class {
color: $brand-theme-color;
}
}
.copyright {
font-size: 28rpx;
padding: 20rpx;
background: #F6F6F6;
color: #666;
border-radius: 10rpx;
margin: 20rpx 0;
line-height: 1.6em;
}
}
}
}
.scorePopup {
background: #fff;
padding: 30rpx;
width: 70vw;
border-radius: 30rpx; //圆角
// 内容
.content {
padding: 30rpx 0;
display: flex; //居中
justify-content: center;
align-items: center;
.text {
color: #FFCA3E;
padding-left: 10rpx;
width: 80rpx;
line-height: 1em;
text-align: right; //右对齐
font-size: 28rpx;
}
}
.footer {
padding: 10rpx 0;
display: flex;
align-items: center;
justify-content: center;
}
}
}
</style>
29. 对接评分接口对壁纸进行滑动提交评分
<script setup>
import {
ref
} from 'vue';
import {
onLoad
} from "@dcloudio/uni-app"
import {
getStatusBarHeight
} from "../../utils/system.js"
import {
apiGetSetupScore
} from "@/api/apis.js"
const maskState = ref(true);
// 弹窗状态
const infoPopup = ref(null);
const scorePopup = ref(null);
const userScore = ref(0)
const classList = ref([]);
// 当前的ID
const currentId = ref(null);
const currentIndex = ref(0)
// 壁纸信息
const currentInfo = ref(null);
// 数组存储浏览过的壁纸
const readImgs = ref([]);
//点击info弹窗
const clickInfo = () => {
infoPopup.value.open();
}
//点击关闭信息弹窗
const clickInfoClose = () => {
infoPopup.value.close();
}
//评分弹窗
const clickScore = () => {
scorePopup.value.open();
}
//关闭评分框
const clickScoreClose = () => {
scorePopup.value.close();
// 初始化
userScore.value = 0;
}
//确认评分
const submitScore = async () => {
// 解构
let {
classid,
_id: wallId
} = currentInfo.value;
// 调用接口,异步请求同步化
let res = await apiGetSetupScore({
classid,
wallId,
userScore: userScore.value
})
//提示
if (res.errCode === 0) {
uni.showToast({
title: "评分成功",
icon: "none"
})
// 评分成功调用关闭弹窗
clickScoreClose();
}
}
//遮罩层状态
const maskChange = () => {
maskState.value = !maskState.value
}
//返回上一页
const goBack = () => {
uni.navigateBack()
}
//获取缓存
const storgClassList = uni.getStorageSync("storgClassList") || [];
classList.value = storgClassList.map(item => {
return {
...item,
picurl: item.smallPicurl.replace("_small.webp", ".jpg")
}
})
onLoad(async (e) => {
// 赋值
currentId.value = e.id;
// findIndex比较每一个_id与传入的id相等
currentIndex.value = classList.value.findIndex(item => item._id == currentId.value)
//赋值 壁纸信息,根据索引值
currentInfo.value = classList.value[currentIndex.value]
// 把浏览过的壁纸索引推入
readImgsFun();
})
const swiperChange = (e) => {
// 赋值索引值
currentIndex.value = e.detail.current;
//赋值 壁纸信息,根据索引值
currentInfo.value = classList.value[currentIndex.value]
// 把滑动过的壁纸索引推入
readImgsFun();
console.log(e);
}
console.log(classList.value);
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)];
}
</script>
<template>
<view class="preview">
<!-- 轮播图 -->
<swiper circular :current="currentIndex" @change="swiperChange">
<swiper-item v-for="(item,index) in classList" :key="item._id">
<image v-if="readImgs.includes(index)" @click="maskChange" :src="item.picurl" mode="aspectFill"></image>
</swiper-item>
</swiper>
<!-- 遮罩层 -->
<view class="mask" v-if="maskState">
<!-- 返回按钮 -->
<!-- #ifndef MP-TOUTIAO -->
<view class="goBack" @click="goBack" :style="{top:getStatusBarHeight()+'px'}">
<uni-icons type="back" color="#fff" size="20"></uni-icons>
</view>
<!-- #endif -->
<!-- 显示进度 动态数据-->
<view class="count">{{currentIndex+1}} / {{classList.length}}</view>
<!-- 时间-->
<view class="time">
<uni-dateformat :date="new Date()" format="hh:mm"></uni-dateformat>
</view>
<!-- 日期 -->
<view class="date">
<uni-dateformat :date="new Date()" format="MM月dd日"></uni-dateformat>
</view>
<!-- 功能按钮 -->
<view class="footer">
<view class="box" @click="clickInfo">
<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">
<uni-icons type="download" size="23"></uni-icons>
<view class="text">下载</view>
</view>
</view>
</view>
<uni-popup ref="infoPopup" type="bottom">
<view class="infoPopup">
<!-- 标题 退出x -->
<view class="popHeader">
<view></view>
<view class="title">壁纸信息</view>
<view class="close" @click="clickInfoClose">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<!-- 滚动条 -->
<scroll-view scroll-y>
<view class="content">
<view class="row">
<view class="label">壁纸ID:</view>
<text selectable class="value">{{currentInfo._id}}</text>
</view>
<!-- <view class="row">
<view class="label">分类:</view>
<text class="value class">明星美女</text>
</view> -->
<view class="row">
<view class="label">发布者:</view>
<text class="value">{{currentInfo.nickname}}</text>
</view>
<view class="row">
<text class="label">评分:</text>
<view class='value roteBox'>
<uni-rate readonly touchable value="4" size="16" />
<text class="score">{{currentInfo.score}}分</text>
</view>
</view>
<view class="row">
<text class="label">摘要:</text>
<view class='value'>
{{currentInfo.description}}
</view>
</view>
<view class="row">
<text class="label">标签:</text>
<view class='value tabs'>
<view class="tab" v-for="tab in currentInfo.tabs">
{{tab}}
</view>
</view>
</view>
<view class="copyright">声明:XXXXXXXXXXX</view>
</view>
</scroll-view>
</view>
</uni-popup>
<uni-popup ref="scorePopup" :is-mask-click="false">
<view class="scorePopup">
<view class="popHeader">
<view></view>
<view class="title">壁纸评分</view>
<view class="close" @click="clickScoreClose()">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<!-- 内容 -->
<view class="content">
<uni-rate v-model="userScore" allowHalf disabled-color="#FFCA3E" />
<text class="text">{{userScore}}分</text>
</view>
<!-- 按钮 -->
<view class="footer">
<button @click="submitScore" :disabled="!userScore " type="default" size="mini" plain>确认评分</button>
</view>
</view>
</uni-popup>
</view>
</template>
<style lang="scss" scoped>
.preview {
width: 100%;
height: 100vh;
position: relative;
swiper {
width: 100%;
height: 100%;
image {
width: 100%;
height: 100%;
}
}
// 信息
.mask {
&>view {
//让mask紧邻的view
position: absolute;
left: 0;
margin: auto;
color: #fff;
right: 0;
width: fit-content; //内容决定宽度
}
.goBack {
width: 38px;
height: 38px;
background: rgba(0, 0, 0, 0.5);
left: 30rpx;
margin-left: 0;
border-radius: 100px;
top: 0;
backdrop-filter: blur(10rpx);
border: 1rpx solid rgba(255, 255, 255, 0.3);
// 图标居中
display: flex;
align-items: center;
justify-content: center;
}
.count {
top: 10vh;
background: rgba(0, 0, 0, 0.3); //背景
font-size: 28rpx; //字号
border-radius: 40rpx; //圆角
padding: 8rpx 28rpx; //上下8 左右28
backdrop-filter: blur(10rpx); //模糊
}
.time {
font-size: 140rpx; //字体大小
top: calc(10vh + 80rpx); //计算函数
font-weight: 100; //字体加粗
line-height: 1em; //行高
text-shadow: 0 4rpx rgba(0, 0, 0, 0.3); //文字阴影
}
.date {
font-size: 34rpx;
top: calc(10vh + 230rpx);
text-shadow: 0 2rpx rgba(0, 0, 0, 0.3);
}
.footer {
background: rgba(255, 255, 255, 0.8);
bottom: 10vh; //以底为基准
width: 65vw;
height: 120rpx;
border-radius: 120rpx; //圆角
color: #000;
display: flex; //一行
justify-content: space-around; //两端对齐
align-items: center;
box-shadow: 0 2rpx 0 rgba(0, 0, 0, 0.1); //阴影
backdrop-filter: blur(20rpx); //模糊
.box {
display: flex;
flex-direction: column; //文本行排列顺序、堆叠的方向
align-items: center;
justify-content: center;
padding: 2rpx 12rpx;
.text {
font-size: 26rpx;
color: $text-font-color-2;
}
}
}
}
// 标题 退出x
.popHeader {
display: flex;
justify-content: space-between; //两端对齐
align-items: center;
.title {
color: $text-font-color-2;
font-size: 26rpx;
}
.close {
padding: 6rpx;
}
}
.infoPopup {
background: #fff;
padding: 30rpx;
border-radius: 30rpx 30rpx 0 0; //左右圆角
overflow: hidden; //超出隐藏
scroll-view {
max-height: 60vh; //最大高度
.content {
// 壁纸id
.row {
display: flex;
padding: 16rpx 0;
font-size: 32rpx;
line-height: 1.7em; //行间距
// 文字(不可选中
.label {
color: $text-font-color-3;
width: 140rpx;
text-align: right;
font-size: 30rpx;
}
// 数据(可选
.value {
flex: 1;
width: 0;
}
.roteBox {
display: flex; //显示一行
align-items: center; //垂直居中
//文字分数
.score {
font-size: 26rpx;
color: $text-font-color-2;
padding-left: 10rpx;
}
}
// 标签组
.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: 1em;
margin: 0 10rpx 10rpx 0;
}
}
.class {
color: $brand-theme-color;
}
}
.copyright {
font-size: 28rpx;
padding: 20rpx;
background: #F6F6F6;
color: #666;
border-radius: 10rpx;
margin: 20rpx 0;
line-height: 1.6em;
}
}
}
}
.scorePopup {
background: #fff;
padding: 30rpx;
width: 70vw;
border-radius: 30rpx; //圆角
// 内容
.content {
padding: 30rpx 0;
display: flex; //居中
justify-content: center;
align-items: center;
.text {
color: #FFCA3E;
padding-left: 10rpx;
width: 80rpx;
line-height: 1em;
text-align: right; //右对齐
font-size: 28rpx;
}
}
.footer {
padding: 10rpx 0;
display: flex;
align-items: center;
justify-content: center;
}
}
}
</style>
30.通过本地缓存修改已评分过的状态
<script setup>
import {
ref
} from 'vue';
import {
onLoad
} from "@dcloudio/uni-app"
import {
getStatusBarHeight
} from "../../utils/system.js"
import {
apiGetSetupScore
} from "@/api/apis.js"
const maskState = ref(true);
// 弹窗状态
const infoPopup = ref(null);
const scorePopup = ref(null);
const userScore = ref(0)
const classList = ref([]);
// 当前的ID
const currentId = ref(null);
const currentIndex = ref(0)
// 壁纸信息
const currentInfo = ref(null);
// 数组存储浏览过的壁纸
const readImgs = ref([]);
// 评分状态,默认未评分
const isScore = ref(false);
//点击info弹窗
const clickInfo = () => {
infoPopup.value.open();
}
//点击关闭信息弹窗
const clickInfoClose = () => {
infoPopup.value.close();
}
//评分弹窗
const clickScore = () => {
// 判断是否存在userScore
if (currentInfo.value.userScore) {
// 改变评分状态
isScore.value = true;
// userScore的值变成数据库的值
userScore.value = currentInfo.value.userScore;
}
scorePopup.value.open();
}
//关闭评分框
const clickScoreClose = () => {
scorePopup.value.close();
// 初始化
userScore.value = 0;
// 评分状态
isScore.value = false;
}
//确认评分
const submitScore = async () => {
// 加载
uni.showLoading({
title: "加载中..."
})
// 解构
let {
classid,
_id: wallId
} = currentInfo.value;
// 调用接口,异步请求同步化
let res = await apiGetSetupScore({
classid,
wallId,
userScore: userScore.value
})
// 结束加载
uni.hideLoading();
//提示
if (res.errCode === 0) {
uni.showToast({
title: "评分成功",
icon: "none"
})
// 当前对象追加userScore
classList.value[currentIndex.value].userScore = userScore.value;
//缓存, 用于显示已评分的壁纸评分
uni.setStorageSync("storgClassList", classList.value);
// 评分成功调用关闭弹窗
clickScoreClose();
}
}
//遮罩层状态
const maskChange = () => {
maskState.value = !maskState.value
}
//返回上一页
const goBack = () => {
uni.navigateBack()
}
//获取缓存
const storgClassList = uni.getStorageSync("storgClassList") || [];
classList.value = storgClassList.map(item => {
return {
...item,
picurl: item.smallPicurl.replace("_small.webp", ".jpg")
}
})
onLoad(async (e) => {
// 赋值
currentId.value = e.id;
// findIndex比较每一个_id与传入的id相等
currentIndex.value = classList.value.findIndex(item => item._id == currentId.value)
//赋值 壁纸信息,根据索引值
currentInfo.value = classList.value[currentIndex.value]
// 把浏览过的壁纸索引推入
readImgsFun();
})
const swiperChange = (e) => {
// 赋值索引值
currentIndex.value = e.detail.current;
//赋值 壁纸信息,根据索引值
currentInfo.value = classList.value[currentIndex.value]
// 把滑动过的壁纸索引推入
readImgsFun();
console.log(e);
}
console.log(classList.value);
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)];
}
</script>
<template>
<view class="preview">
<!-- 轮播图 -->
<swiper circular :current="currentIndex" @change="swiperChange">
<swiper-item v-for="(item,index) in classList" :key="item._id">
<image v-if="readImgs.includes(index)" @click="maskChange" :src="item.picurl" mode="aspectFill"></image>
</swiper-item>
</swiper>
<!-- 遮罩层 -->
<view class="mask" v-if="maskState">
<!-- 返回按钮 -->
<!-- #ifndef MP-TOUTIAO -->
<view class="goBack" @click="goBack" :style="{top:getStatusBarHeight()+'px'}">
<uni-icons type="back" color="#fff" size="20"></uni-icons>
</view>
<!-- #endif -->
<!-- 显示进度 动态数据-->
<view class="count">{{currentIndex+1}} / {{classList.length}}</view>
<!-- 时间-->
<view class="time">
<uni-dateformat :date="new Date()" format="hh:mm"></uni-dateformat>
</view>
<!-- 日期 -->
<view class="date">
<uni-dateformat :date="new Date()" format="MM月dd日"></uni-dateformat>
</view>
<!-- 功能按钮 -->
<view class="footer">
<view class="box" @click="clickInfo">
<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">
<uni-icons type="download" size="23"></uni-icons>
<view class="text">下载</view>
</view>
</view>
</view>
<uni-popup ref="infoPopup" type="bottom">
<view class="infoPopup">
<!-- 标题 退出x -->
<view class="popHeader">
<view></view>
<view class="title">壁纸信息</view>
<view class="close" @click="clickInfoClose">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<!-- 滚动条 -->
<scroll-view scroll-y>
<view class="content">
<view class="row">
<view class="label">壁纸ID:</view>
<text selectable class="value">{{currentInfo._id}}</text>
</view>
<!-- <view class="row">
<view class="label">分类:</view>
<text class="value class">明星美女</text>
</view> -->
<view class="row">
<view class="label">发布者:</view>
<text class="value">{{currentInfo.nickname}}</text>
</view>
<view class="row">
<text class="label">评分:</text>
<view class='value roteBox'>
<uni-rate readonly touchable value="4" size="16" />
<text class="score">{{currentInfo.score}}分</text>
</view>
</view>
<view class="row">
<text class="label">摘要:</text>
<view class='value'>
{{currentInfo.description}}
</view>
</view>
<view class="row">
<text class="label">标签:</text>
<view class='value tabs'>
<view class="tab" v-for="tab in currentInfo.tabs">
{{tab}}
</view>
</view>
</view>
<view class="copyright">声明:XXXXXXXXXXX</view>
</view>
</scroll-view>
</view>
</uni-popup>
<uni-popup ref="scorePopup" :is-mask-click="false">
<view class="scorePopup">
<view class="popHeader">
<view></view>
<view class="title">{{isScore?'评分过了~':'壁纸评分'}}</view>
<view class="close" @click="clickScoreClose()">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<!-- 内容 -->
<view class="content">
<uni-rate v-model="userScore" allowHalf :disabled="isScore" disabled-color="#FFCA3E" />
<text class="text">{{userScore}}分</text>
</view>
<!-- 按钮 -->
<view class="footer">
<button @click="submitScore" :disabled="!userScore || isScore" type="default" size="mini"
plain>确认评分</button>
</view>
</view>
</uni-popup>
</view>
</template>
<style lang="scss" scoped>
.preview {
width: 100%;
height: 100vh;
position: relative;
swiper {
width: 100%;
height: 100%;
image {
width: 100%;
height: 100%;
}
}
// 信息
.mask {
&>view {
//让mask紧邻的view
position: absolute;
left: 0;
margin: auto;
color: #fff;
right: 0;
width: fit-content; //内容决定宽度
}
.goBack {
width: 38px;
height: 38px;
background: rgba(0, 0, 0, 0.5);
left: 30rpx;
margin-left: 0;
border-radius: 100px;
top: 0;
backdrop-filter: blur(10rpx);
border: 1rpx solid rgba(255, 255, 255, 0.3);
// 图标居中
display: flex;
align-items: center;
justify-content: center;
}
.count {
top: 10vh;
background: rgba(0, 0, 0, 0.3); //背景
font-size: 28rpx; //字号
border-radius: 40rpx; //圆角
padding: 8rpx 28rpx; //上下8 左右28
backdrop-filter: blur(10rpx); //模糊
}
.time {
font-size: 140rpx; //字体大小
top: calc(10vh + 80rpx); //计算函数
font-weight: 100; //字体加粗
line-height: 1em; //行高
text-shadow: 0 4rpx rgba(0, 0, 0, 0.3); //文字阴影
}
.date {
font-size: 34rpx;
top: calc(10vh + 230rpx);
text-shadow: 0 2rpx rgba(0, 0, 0, 0.3);
}
.footer {
background: rgba(255, 255, 255, 0.8);
bottom: 10vh; //以底为基准
width: 65vw;
height: 120rpx;
border-radius: 120rpx; //圆角
color: #000;
display: flex; //一行
justify-content: space-around; //两端对齐
align-items: center;
box-shadow: 0 2rpx 0 rgba(0, 0, 0, 0.1); //阴影
backdrop-filter: blur(20rpx); //模糊
.box {
display: flex;
flex-direction: column; //文本行排列顺序、堆叠的方向
align-items: center;
justify-content: center;
padding: 2rpx 12rpx;
.text {
font-size: 26rpx;
color: $text-font-color-2;
}
}
}
}
// 标题 退出x
.popHeader {
display: flex;
justify-content: space-between; //两端对齐
align-items: center;
.title {
color: $text-font-color-2;
font-size: 26rpx;
}
.close {
padding: 6rpx;
}
}
.infoPopup {
background: #fff;
padding: 30rpx;
border-radius: 30rpx 30rpx 0 0; //左右圆角
overflow: hidden; //超出隐藏
scroll-view {
max-height: 60vh; //最大高度
.content {
// 壁纸id
.row {
display: flex;
padding: 16rpx 0;
font-size: 32rpx;
line-height: 1.7em; //行间距
// 文字(不可选中
.label {
color: $text-font-color-3;
width: 140rpx;
text-align: right;
font-size: 30rpx;
}
// 数据(可选
.value {
flex: 1;
width: 0;
}
.roteBox {
display: flex; //显示一行
align-items: center; //垂直居中
//文字分数
.score {
font-size: 26rpx;
color: $text-font-color-2;
padding-left: 10rpx;
}
}
// 标签组
.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: 1em;
margin: 0 10rpx 10rpx 0;
}
}
.class {
color: $brand-theme-color;
}
}
.copyright {
font-size: 28rpx;
padding: 20rpx;
background: #F6F6F6;
color: #666;
border-radius: 10rpx;
margin: 20rpx 0;
line-height: 1.6em;
}
}
}
}
.scorePopup {
background: #fff;
padding: 30rpx;
width: 70vw;
border-radius: 30rpx; //圆角
// 内容
.content {
padding: 30rpx 0;
display: flex; //居中
justify-content: center;
align-items: center;
.text {
color: #FFCA3E;
padding-left: 10rpx;
width: 80rpx;
line-height: 1em;
text-align: right; //右对齐
font-size: 28rpx;
}
}
.footer {
padding: 10rpx 0;
display: flex;
align-items: center;
justify-content: center;
}
}
}
</style>
31. saveImageToPhotosAlbum保存壁纸到相册
uni.saveImageToPhotosAlbum(OBJECT) | uni-app官网
OBJECT 参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
filePath | String | 是 | 图片文件路径,可以是临时文件路径也可以是永久文件路径,不支持网络图片路径 |
uni.getImageInfo(OBJECT) | uni-app官网
小程序下获取网络图片信息需先配置download域名白名单才能生效
OBJECT 参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
src | String | 是 | 图片的路径,可以是相对路径,临时文件路径,存储文件路径,网络图片路径 |
小程序
<script setup>
import {
ref
} from 'vue';
import {
onLoad
} from "@dcloudio/uni-app"
import {
getStatusBarHeight
} from "../../utils/system.js"
import {
apiGetSetupScore
} from "@/api/apis.js"
const maskState = ref(true);
// 弹窗状态
const infoPopup = ref(null);
const scorePopup = ref(null);
const userScore = ref(0)
const classList = ref([]);
// 当前的ID
const currentId = ref(null);
const currentIndex = ref(0)
// 壁纸信息
const currentInfo = ref(null);
// 数组存储浏览过的壁纸
const readImgs = ref([]);
// 评分状态,默认未评分
const isScore = ref(false);
//点击info弹窗
const clickInfo = () => {
infoPopup.value.open();
}
//点击关闭信息弹窗
const clickInfoClose = () => {
infoPopup.value.close();
}
//评分弹窗
const clickScore = () => {
// 判断是否存在userScore
if (currentInfo.value.userScore) {
// 改变评分状态
isScore.value = true;
// userScore的值变成数据库的值
userScore.value = currentInfo.value.userScore;
}
scorePopup.value.open();
}
//关闭评分框
const clickScoreClose = () => {
scorePopup.value.close();
// 初始化
userScore.value = 0;
// 评分状态
isScore.value = false;
}
//确认评分
const submitScore = async () => {
// 加载
uni.showLoading({
title: "加载中..."
})
// 解构
let {
classid,
_id: wallId
} = currentInfo.value;
// 调用接口,异步请求同步化
let res = await apiGetSetupScore({
classid,
wallId,
userScore: userScore.value
})
// 结束加载
uni.hideLoading();
//提示
if (res.errCode === 0) {
uni.showToast({
title: "评分成功",
icon: "none"
})
// 当前对象追加userScore
classList.value[currentIndex.value].userScore = userScore.value;
//缓存, 用于显示已评分的壁纸评分
uni.setStorageSync("storgClassList", classList.value);
// 评分成功调用关闭弹窗
clickScoreClose();
}
}
//遮罩层状态
const maskChange = () => {
maskState.value = !maskState.value
}
//返回上一页
const goBack = () => {
uni.navigateBack()
}
//获取缓存
const storgClassList = uni.getStorageSync("storgClassList") || [];
classList.value = storgClassList.map(item => {
return {
...item,
picurl: item.smallPicurl.replace("_small.webp", ".jpg")
}
})
onLoad(async (e) => {
// 赋值
currentId.value = e.id;
// findIndex比较每一个_id与传入的id相等
currentIndex.value = classList.value.findIndex(item => item._id == currentId.value)
//赋值 壁纸信息,根据索引值
currentInfo.value = classList.value[currentIndex.value]
// 把浏览过的壁纸索引推入
readImgsFun();
})
const swiperChange = (e) => {
// 赋值索引值
currentIndex.value = e.detail.current;
//赋值 壁纸信息,根据索引值
currentInfo.value = classList.value[currentIndex.value]
// 把滑动过的壁纸索引推入
readImgsFun();
console.log(e);
}
console.log(classList.value);
//点击下载
const clickDownload = async () => {
// #ifdef H5
uni.showModal({
content: "请长按保存壁纸",
showCancel: false
})
// #endif
// 除了H5,都适用uni.saveImageToPhotosAlbum(OBJECT)
// #ifndef H5
uni.getImageInfo({
src: currentInfo.value.picurl,
success: (res) => {
uni.saveImageToPhotosAlbum({
filePath: res.path,
success: (res) => {
uni.showToast({
title: "保存成功,请到相册查看",
icon: "none"
})
}
}
})
// #endif
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)];
}
</script>
<template>
<view class="preview">
<!-- 轮播图 -->
<swiper circular :current="currentIndex" @change="swiperChange">
<swiper-item v-for="(item,index) in classList" :key="item._id">
<image v-if="readImgs.includes(index)" @click="maskChange" :src="item.picurl" mode="aspectFill"></image>
</swiper-item>
</swiper>
<!-- 遮罩层 -->
<view class="mask" v-if="maskState">
<!-- 返回按钮 -->
<!-- #ifndef MP-TOUTIAO -->
<view class="goBack" @click="goBack" :style="{top:getStatusBarHeight()+'px'}">
<uni-icons type="back" color="#fff" size="20"></uni-icons>
</view>
<!-- #endif -->
<!-- 显示进度 动态数据-->
<view class="count">{{currentIndex+1}} / {{classList.length}}</view>
<!-- 时间-->
<view class="time">
<uni-dateformat :date="new Date()" format="hh:mm"></uni-dateformat>
</view>
<!-- 日期 -->
<view class="date">
<uni-dateformat :date="new Date()" format="MM月dd日"></uni-dateformat>
</view>
<!-- 功能按钮 -->
<view class="footer">
<view class="box" @click="clickInfo">
<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="23"></uni-icons>
<view class="text">下载</view>
</view>
</view>
</view>
<uni-popup ref="infoPopup" type="bottom">
<view class="infoPopup">
<!-- 标题 退出x -->
<view class="popHeader">
<view></view>
<view class="title">壁纸信息</view>
<view class="close" @click="clickInfoClose">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<!-- 滚动条 -->
<scroll-view scroll-y>
<view class="content">
<view class="row">
<view class="label">壁纸ID:</view>
<text selectable class="value">{{currentInfo._id}}</text>
</view>
<!-- <view class="row">
<view class="label">分类:</view>
<text class="value class">明星美女</text>
</view> -->
<view class="row">
<view class="label">发布者:</view>
<text class="value">{{currentInfo.nickname}}</text>
</view>
<view class="row">
<text class="label">评分:</text>
<view class='value roteBox'>
<uni-rate readonly touchable value="4" size="16" />
<text class="score">{{currentInfo.score}}分</text>
</view>
</view>
<view class="row">
<text class="label">摘要:</text>
<view class='value'>
{{currentInfo.description}}
</view>
</view>
<view class="row">
<text class="label">标签:</text>
<view class='value tabs'>
<view class="tab" v-for="tab in currentInfo.tabs">
{{tab}}
</view>
</view>
</view>
<view class="copyright">声明:XXXXXXXXXXX</view>
</view>
</scroll-view>
</view>
</uni-popup>
<uni-popup ref="scorePopup" :is-mask-click="false">
<view class="scorePopup">
<view class="popHeader">
<view></view>
<view class="title">{{isScore?'评分过了~':'壁纸评分'}}</view>
<view class="close" @click="clickScoreClose()">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<!-- 内容 -->
<view class="content">
<uni-rate v-model="userScore" allowHalf :disabled="isScore" disabled-color="#FFCA3E" />
<text class="text">{{userScore}}分</text>
</view>
<!-- 按钮 -->
<view class="footer">
<button @click="submitScore" :disabled="!userScore || isScore" type="default" size="mini"
plain>确认评分</button>
</view>
</view>
</uni-popup>
</view>
</template>
<style lang="scss" scoped>
.preview {
width: 100%;
height: 100vh;
position: relative;
swiper {
width: 100%;
height: 100%;
image {
width: 100%;
height: 100%;
}
}
// 信息
.mask {
&>view {
//让mask紧邻的view
position: absolute;
left: 0;
margin: auto;
color: #fff;
right: 0;
width: fit-content; //内容决定宽度
}
.goBack {
width: 38px;
height: 38px;
background: rgba(0, 0, 0, 0.5);
left: 30rpx;
margin-left: 0;
border-radius: 100px;
top: 0;
backdrop-filter: blur(10rpx);
border: 1rpx solid rgba(255, 255, 255, 0.3);
// 图标居中
display: flex;
align-items: center;
justify-content: center;
}
.count {
top: 10vh;
background: rgba(0, 0, 0, 0.3); //背景
font-size: 28rpx; //字号
border-radius: 40rpx; //圆角
padding: 8rpx 28rpx; //上下8 左右28
backdrop-filter: blur(10rpx); //模糊
}
.time {
font-size: 140rpx; //字体大小
top: calc(10vh + 80rpx); //计算函数
font-weight: 100; //字体加粗
line-height: 1em; //行高
text-shadow: 0 4rpx rgba(0, 0, 0, 0.3); //文字阴影
}
.date {
font-size: 34rpx;
top: calc(10vh + 230rpx);
text-shadow: 0 2rpx rgba(0, 0, 0, 0.3);
}
.footer {
background: rgba(255, 255, 255, 0.8);
bottom: 10vh; //以底为基准
width: 65vw;
height: 120rpx;
border-radius: 120rpx; //圆角
color: #000;
display: flex; //一行
justify-content: space-around; //两端对齐
align-items: center;
box-shadow: 0 2rpx 0 rgba(0, 0, 0, 0.1); //阴影
backdrop-filter: blur(20rpx); //模糊
.box {
display: flex;
flex-direction: column; //文本行排列顺序、堆叠的方向
align-items: center;
justify-content: center;
padding: 2rpx 12rpx;
.text {
font-size: 26rpx;
color: $text-font-color-2;
}
}
}
}
// 标题 退出x
.popHeader {
display: flex;
justify-content: space-between; //两端对齐
align-items: center;
.title {
color: $text-font-color-2;
font-size: 26rpx;
}
.close {
padding: 6rpx;
}
}
.infoPopup {
background: #fff;
padding: 30rpx;
border-radius: 30rpx 30rpx 0 0; //左右圆角
overflow: hidden; //超出隐藏
scroll-view {
max-height: 60vh; //最大高度
.content {
// 壁纸id
.row {
display: flex;
padding: 16rpx 0;
font-size: 32rpx;
line-height: 1.7em; //行间距
// 文字(不可选中
.label {
color: $text-font-color-3;
width: 140rpx;
text-align: right;
font-size: 30rpx;
}
// 数据(可选
.value {
flex: 1;
width: 0;
}
.roteBox {
display: flex; //显示一行
align-items: center; //垂直居中
//文字分数
.score {
font-size: 26rpx;
color: $text-font-color-2;
padding-left: 10rpx;
}
}
// 标签组
.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: 1em;
margin: 0 10rpx 10rpx 0;
}
}
.class {
color: $brand-theme-color;
}
}
.copyright {
font-size: 28rpx;
padding: 20rpx;
background: #F6F6F6;
color: #666;
border-radius: 10rpx;
margin: 20rpx 0;
line-height: 1.6em;
}
}
}
}
.scorePopup {
background: #fff;
padding: 30rpx;
width: 70vw;
border-radius: 30rpx; //圆角
// 内容
.content {
padding: 30rpx 0;
display: flex; //居中
justify-content: center;
align-items: center;
.text {
color: #FFCA3E;
padding-left: 10rpx;
width: 80rpx;
line-height: 1em;
text-align: right; //右对齐
font-size: 28rpx;
}
}
.footer {
padding: 10rpx 0;
display: flex;
align-items: center;
justify-content: center;
}
}
}
</style>
32. openSetting调用客户端授权信息及各种异常处理
uni.openSetting(OBJECT) | uni-app官网
调起客户端小程序设置界面,返回用户设置的操作结果。
<script setup>
import {
ref
} from 'vue';
import {
onLoad
} from "@dcloudio/uni-app"
import {
getStatusBarHeight
} from "../../utils/system.js"
import {
apiGetSetupScore
} from "@/api/apis.js"
const maskState = ref(true);
// 弹窗状态
const infoPopup = ref(null);
const scorePopup = ref(null);
const userScore = ref(0)
const classList = ref([]);
// 当前的ID
const currentId = ref(null);
const currentIndex = ref(0)
// 壁纸信息
const currentInfo = ref(null);
// 数组存储浏览过的壁纸
const readImgs = ref([]);
// 评分状态,默认未评分
const isScore = ref(false);
//点击info弹窗
const clickInfo = () => {
infoPopup.value.open();
}
//点击关闭信息弹窗
const clickInfoClose = () => {
infoPopup.value.close();
}
//评分弹窗
const clickScore = () => {
// 判断是否存在userScore
if (currentInfo.value.userScore) {
// 改变评分状态
isScore.value = true;
// userScore的值变成数据库的值
userScore.value = currentInfo.value.userScore;
}
scorePopup.value.open();
}
//关闭评分框
const clickScoreClose = () => {
scorePopup.value.close();
// 初始化
userScore.value = 0;
// 评分状态
isScore.value = false;
}
//确认评分
const submitScore = async () => {
// 加载
uni.showLoading({
title: "加载中..."
})
// 解构
let {
classid,
_id: wallId
} = currentInfo.value;
// 调用接口,异步请求同步化
let res = await apiGetSetupScore({
classid,
wallId,
userScore: userScore.value
})
// 结束加载
uni.hideLoading();
//提示
if (res.errCode === 0) {
uni.showToast({
title: "评分成功",
icon: "none"
})
// 当前对象追加userScore
classList.value[currentIndex.value].userScore = userScore.value;
//缓存, 用于显示已评分的壁纸评分
uni.setStorageSync("storgClassList", classList.value);
// 评分成功调用关闭弹窗
clickScoreClose();
}
}
//遮罩层状态
const maskChange = () => {
maskState.value = !maskState.value
}
//返回上一页
const goBack = () => {
uni.navigateBack()
}
//获取缓存
const storgClassList = uni.getStorageSync("storgClassList") || [];
classList.value = storgClassList.map(item => {
return {
...item,
picurl: item.smallPicurl.replace("_small.webp", ".jpg")
}
})
onLoad(async (e) => {
// 赋值
currentId.value = e.id;
// findIndex比较每一个_id与传入的id相等
currentIndex.value = classList.value.findIndex(item => item._id == currentId.value)
//赋值 壁纸信息,根据索引值
currentInfo.value = classList.value[currentIndex.value]
// 把浏览过的壁纸索引推入
readImgsFun();
})
const swiperChange = (e) => {
// 赋值索引值
currentIndex.value = e.detail.current;
//赋值 壁纸信息,根据索引值
currentInfo.value = classList.value[currentIndex.value]
// 把滑动过的壁纸索引推入
readImgsFun();
console.log(e);
}
console.log(classList.value);
//点击下载
const clickDownload = async () => {
// #ifdef H5
uni.showModal({
content: "请长按保存壁纸",
showCancel: false
})
// #endif
// 除了H5,都适用uni.saveImageToPhotosAlbum(OBJECT)
// #ifndef H5
uni.showLoading({
title: "下载中...",
mask: true
})
// 获取图片信息
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: "需要授权保存相册",
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();
}
})
}
})
// #endif
}
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)];
}
</script>
<template>
<view class="preview">
<!-- 轮播图 -->
<swiper circular :current="currentIndex" @change="swiperChange">
<swiper-item v-for="(item,index) in classList" :key="item._id">
<image v-if="readImgs.includes(index)" @click="maskChange" :src="item.picurl" mode="aspectFill"></image>
</swiper-item>
</swiper>
<!-- 遮罩层 -->
<view class="mask" v-if="maskState">
<!-- 返回按钮 -->
<!-- #ifndef MP-TOUTIAO -->
<view class="goBack" @click="goBack" :style="{top:getStatusBarHeight()+'px'}">
<uni-icons type="back" color="#fff" size="20"></uni-icons>
</view>
<!-- #endif -->
<!-- 显示进度 动态数据-->
<view class="count">{{currentIndex+1}} / {{classList.length}}</view>
<!-- 时间-->
<view class="time">
<uni-dateformat :date="new Date()" format="hh:mm"></uni-dateformat>
</view>
<!-- 日期 -->
<view class="date">
<uni-dateformat :date="new Date()" format="MM月dd日"></uni-dateformat>
</view>
<!-- 功能按钮 -->
<view class="footer">
<view class="box" @click="clickInfo">
<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="23"></uni-icons>
<view class="text">下载</view>
</view>
</view>
</view>
<uni-popup ref="infoPopup" type="bottom">
<view class="infoPopup">
<!-- 标题 退出x -->
<view class="popHeader">
<view></view>
<view class="title">壁纸信息</view>
<view class="close" @click="clickInfoClose">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<!-- 滚动条 -->
<scroll-view scroll-y>
<view class="content">
<view class="row">
<view class="label">壁纸ID:</view>
<text selectable class="value">{{currentInfo._id}}</text>
</view>
<!-- <view class="row">
<view class="label">分类:</view>
<text class="value class">明星美女</text>
</view> -->
<view class="row">
<view class="label">发布者:</view>
<text class="value">{{currentInfo.nickname}}</text>
</view>
<view class="row">
<text class="label">评分:</text>
<view class='value roteBox'>
<uni-rate readonly touchable value="4" size="16" />
<text class="score">{{currentInfo.score}}分</text>
</view>
</view>
<view class="row">
<text class="label">摘要:</text>
<view class='value'>
{{currentInfo.description}}
</view>
</view>
<view class="row">
<text class="label">标签:</text>
<view class='value tabs'>
<view class="tab" v-for="tab in currentInfo.tabs">
{{tab}}
</view>
</view>
</view>
<view class="copyright">声明:XXXXXXXXXXX</view>
</view>
</scroll-view>
</view>
</uni-popup>
<uni-popup ref="scorePopup" :is-mask-click="false">
<view class="scorePopup">
<view class="popHeader">
<view></view>
<view class="title">{{isScore?'评分过了~':'壁纸评分'}}</view>
<view class="close" @click="clickScoreClose()">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<!-- 内容 -->
<view class="content">
<uni-rate v-model="userScore" allowHalf :disabled="isScore" disabled-color="#FFCA3E" />
<text class="text">{{userScore}}分</text>
</view>
<!-- 按钮 -->
<view class="footer">
<button @click="submitScore" :disabled="!userScore || isScore" type="default" size="mini"
plain>确认评分</button>
</view>
</view>
</uni-popup>
</view>
</template>
<style lang="scss" scoped>
.preview {
width: 100%;
height: 100vh;
position: relative;
swiper {
width: 100%;
height: 100%;
image {
width: 100%;
height: 100%;
}
}
// 信息
.mask {
&>view {
//让mask紧邻的view
position: absolute;
left: 0;
margin: auto;
color: #fff;
right: 0;
width: fit-content; //内容决定宽度
}
.goBack {
width: 38px;
height: 38px;
background: rgba(0, 0, 0, 0.5);
left: 30rpx;
margin-left: 0;
border-radius: 100px;
top: 0;
backdrop-filter: blur(10rpx);
border: 1rpx solid rgba(255, 255, 255, 0.3);
// 图标居中
display: flex;
align-items: center;
justify-content: center;
}
.count {
top: 10vh;
background: rgba(0, 0, 0, 0.3); //背景
font-size: 28rpx; //字号
border-radius: 40rpx; //圆角
padding: 8rpx 28rpx; //上下8 左右28
backdrop-filter: blur(10rpx); //模糊
}
.time {
font-size: 140rpx; //字体大小
top: calc(10vh + 80rpx); //计算函数
font-weight: 100; //字体加粗
line-height: 1em; //行高
text-shadow: 0 4rpx rgba(0, 0, 0, 0.3); //文字阴影
}
.date {
font-size: 34rpx;
top: calc(10vh + 230rpx);
text-shadow: 0 2rpx rgba(0, 0, 0, 0.3);
}
.footer {
background: rgba(255, 255, 255, 0.8);
bottom: 10vh; //以底为基准
width: 65vw;
height: 120rpx;
border-radius: 120rpx; //圆角
color: #000;
display: flex; //一行
justify-content: space-around; //两端对齐
align-items: center;
box-shadow: 0 2rpx 0 rgba(0, 0, 0, 0.1); //阴影
backdrop-filter: blur(20rpx); //模糊
.box {
display: flex;
flex-direction: column; //文本行排列顺序、堆叠的方向
align-items: center;
justify-content: center;
padding: 2rpx 12rpx;
.text {
font-size: 26rpx;
color: $text-font-color-2;
}
}
}
}
// 标题 退出x
.popHeader {
display: flex;
justify-content: space-between; //两端对齐
align-items: center;
.title {
color: $text-font-color-2;
font-size: 26rpx;
}
.close {
padding: 6rpx;
}
}
.infoPopup {
background: #fff;
padding: 30rpx;
border-radius: 30rpx 30rpx 0 0; //左右圆角
overflow: hidden; //超出隐藏
scroll-view {
max-height: 60vh; //最大高度
.content {
// 壁纸id
.row {
display: flex;
padding: 16rpx 0;
font-size: 32rpx;
line-height: 1.7em; //行间距
// 文字(不可选中
.label {
color: $text-font-color-3;
width: 140rpx;
text-align: right;
font-size: 30rpx;
}
// 数据(可选
.value {
flex: 1;
width: 0;
}
.roteBox {
display: flex; //显示一行
align-items: center; //垂直居中
//文字分数
.score {
font-size: 26rpx;
color: $text-font-color-2;
padding-left: 10rpx;
}
}
// 标签组
.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: 1em;
margin: 0 10rpx 10rpx 0;
}
}
.class {
color: $brand-theme-color;
}
}
.copyright {
font-size: 28rpx;
padding: 20rpx;
background: #F6F6F6;
color: #666;
border-radius: 10rpx;
margin: 20rpx 0;
line-height: 1.6em;
}
}
}
}
.scorePopup {
background: #fff;
padding: 30rpx;
width: 70vw;
border-radius: 30rpx; //圆角
// 内容
.content {
padding: 30rpx 0;
display: flex; //居中
justify-content: center;
align-items: center;
.text {
color: #FFCA3E;
padding-left: 10rpx;
width: 80rpx;
line-height: 1em;
text-align: right; //右对齐
font-size: 28rpx;
}
}
.footer {
padding: 10rpx 0;
display: flex;
align-items: center;
justify-content: center;
}
}
}
</style>
33. try{}catch处理同步请求下载记录异常处理
<script setup>
import {
ref
} from 'vue';
import {
onLoad
} from "@dcloudio/uni-app"
import {
getStatusBarHeight
} from "../../utils/system.js"
import {
apiGetSetupScore,
apiWriteDownload
} from "@/api/apis.js"
const maskState = ref(true);
// 弹窗状态
const infoPopup = ref(null);
const scorePopup = ref(null);
const userScore = ref(0)
const classList = ref([]);
// 当前的ID
const currentId = ref(null);
const currentIndex = ref(0)
// 壁纸信息,设为空对象,不会报错
const currentInfo = ref({});
// 数组存储浏览过的壁纸
const readImgs = ref([]);
// 评分状态,默认未评分
const isScore = ref(false);
//点击info弹窗
const clickInfo = () => {
infoPopup.value.open();
}
//点击关闭信息弹窗
const clickInfoClose = () => {
infoPopup.value.close();
}
//评分弹窗
const clickScore = () => {
// 判断是否存在userScore
if (currentInfo.value.userScore) {
// 改变评分状态
isScore.value = true;
// userScore的值变成数据库的值
userScore.value = currentInfo.value.userScore;
}
scorePopup.value.open();
}
//关闭评分框
const clickScoreClose = () => {
scorePopup.value.close();
// 初始化
userScore.value = 0;
// 评分状态
isScore.value = false;
}
//确认评分
const submitScore = async () => {
// 加载
uni.showLoading({
title: "加载中..."
})
// 解构
let {
classid,
_id: wallId
} = currentInfo.value;
// 调用接口,异步请求同步化
let res = await apiGetSetupScore({
classid,
wallId,
userScore: userScore.value
})
// 结束加载
uni.hideLoading();
//提示
if (res.errCode === 0) {
uni.showToast({
title: "评分成功",
icon: "none"
})
// 当前对象追加userScore
classList.value[currentIndex.value].userScore = userScore.value;
//缓存, 用于显示已评分的壁纸评分
uni.setStorageSync("storgClassList", classList.value);
// 评分成功调用关闭弹窗
clickScoreClose();
}
}
//遮罩层状态
const maskChange = () => {
maskState.value = !maskState.value
}
//返回上一页
const goBack = () => {
uni.navigateBack()
}
//获取缓存
const storgClassList = uni.getStorageSync("storgClassList") || [];
classList.value = storgClassList.map(item => {
return {
...item,
picurl: item.smallPicurl.replace("_small.webp", ".jpg")
}
})
onLoad(async (e) => {
// 赋值
currentId.value = e.id;
// findIndex比较每一个_id与传入的id相等
currentIndex.value = classList.value.findIndex(item => item._id == currentId.value)
//赋值 壁纸信息,根据索引值
currentInfo.value = classList.value[currentIndex.value]
// 把浏览过的壁纸索引推入
readImgsFun();
})
const swiperChange = (e) => {
// 赋值索引值
currentIndex.value = e.detail.current;
//赋值 壁纸信息,根据索引值
currentInfo.value = classList.value[currentIndex.value]
// 把滑动过的壁纸索引推入
readImgsFun();
console.log(e);
}
console.log(classList.value);
//点击下载
const clickDownload = async () => {
// #ifdef H5
uni.showModal({
content: "请长按保存壁纸",
showCancel: false
})
// #endif
// 除了H5,都适用uni.saveImageToPhotosAlbum(OBJECT)
// #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: "需要授权保存相册",
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
}
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)];
}
</script>
<template>
<view class="preview">
<!-- 轮播图 -->
<swiper circular :current="currentIndex" @change="swiperChange">
<swiper-item v-for="(item,index) in classList" :key="item._id">
<image v-if="readImgs.includes(index)" @click="maskChange" :src="item.picurl" mode="aspectFill"></image>
</swiper-item>
</swiper>
<!-- 遮罩层 -->
<view class="mask" v-if="maskState">
<!-- 返回按钮 -->
<!-- #ifndef MP-TOUTIAO -->
<view class="goBack" @click="goBack" :style="{top:getStatusBarHeight()+'px'}">
<uni-icons type="back" color="#fff" size="20"></uni-icons>
</view>
<!-- #endif -->
<!-- 显示进度 动态数据-->
<view class="count">{{currentIndex+1}} / {{classList.length}}</view>
<!-- 时间-->
<view class="time">
<uni-dateformat :date="new Date()" format="hh:mm"></uni-dateformat>
</view>
<!-- 日期 -->
<view class="date">
<uni-dateformat :date="new Date()" format="MM月dd日"></uni-dateformat>
</view>
<!-- 功能按钮 -->
<view class="footer">
<view class="box" @click="clickInfo">
<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="23"></uni-icons>
<view class="text">下载</view>
</view>
</view>
</view>
<uni-popup ref="infoPopup" type="bottom">
<view class="infoPopup">
<!-- 标题 退出x -->
<view class="popHeader">
<view></view>
<view class="title">壁纸信息</view>
<view class="close" @click="clickInfoClose">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<!-- 滚动条 -->
<scroll-view scroll-y>
<view class="content">
<view class="row">
<view class="label">壁纸ID:</view>
<text selectable class="value">{{currentInfo._id}}</text>
</view>
<!-- <view class="row">
<view class="label">分类:</view>
<text class="value class">明星美女</text>
</view> -->
<view class="row">
<view class="label">发布者:</view>
<text class="value">{{currentInfo.nickname}}</text>
</view>
<view class="row">
<text class="label">评分:</text>
<view class='value roteBox'>
<uni-rate readonly touchable value="4" size="16" />
<text class="score">{{currentInfo.score}}分</text>
</view>
</view>
<view class="row">
<text class="label">摘要:</text>
<view class='value'>
{{currentInfo.description}}
</view>
</view>
<view class="row">
<text class="label">标签:</text>
<view class='value tabs'>
<view class="tab" v-for="tab in currentInfo.tabs" :key="tab">
{{tab}}
</view>
</view>
</view>
<view class="copyright">声明:XXXXXXXXXXX</view>
</view>
</scroll-view>
</view>
</uni-popup>
<uni-popup ref="scorePopup" :is-mask-click="false">
<view class="scorePopup">
<view class="popHeader">
<view></view>
<view class="title">{{isScore?'评分过了~':'壁纸评分'}}</view>
<view class="close" @click="clickScoreClose()">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<!-- 内容 -->
<view class="content">
<uni-rate v-model="userScore" allowHalf :disabled="isScore" disabled-color="#FFCA3E" />
<text class="text">{{userScore}}分</text>
</view>
<!-- 按钮 -->
<view class="footer">
<button @click="submitScore" :disabled="!userScore || isScore" type="default" size="mini"
plain>确认评分</button>
</view>
</view>
</uni-popup>
</view>
</template>
<style lang="scss" scoped>
.preview {
width: 100%;
height: 100vh;
position: relative;
swiper {
width: 100%;
height: 100%;
image {
width: 100%;
height: 100%;
}
}
// 信息
.mask {
&>view {
//让mask紧邻的view
position: absolute;
left: 0;
margin: auto;
color: #fff;
right: 0;
width: fit-content; //内容决定宽度
}
.goBack {
width: 38px;
height: 38px;
background: rgba(0, 0, 0, 0.5);
left: 30rpx;
margin-left: 0;
border-radius: 100px;
top: 0;
backdrop-filter: blur(10rpx);
border: 1rpx solid rgba(255, 255, 255, 0.3);
// 图标居中
display: flex;
align-items: center;
justify-content: center;
}
.count {
top: 10vh;
background: rgba(0, 0, 0, 0.3); //背景
font-size: 28rpx; //字号
border-radius: 40rpx; //圆角
padding: 8rpx 28rpx; //上下8 左右28
backdrop-filter: blur(10rpx); //模糊
}
.time {
font-size: 140rpx; //字体大小
top: calc(10vh + 80rpx); //计算函数
font-weight: 100; //字体加粗
line-height: 1em; //行高
text-shadow: 0 4rpx rgba(0, 0, 0, 0.3); //文字阴影
}
.date {
font-size: 34rpx;
top: calc(10vh + 230rpx);
text-shadow: 0 2rpx rgba(0, 0, 0, 0.3);
}
.footer {
background: rgba(255, 255, 255, 0.8);
bottom: 10vh; //以底为基准
width: 65vw;
height: 120rpx;
border-radius: 120rpx; //圆角
color: #000;
display: flex; //一行
justify-content: space-around; //两端对齐
align-items: center;
box-shadow: 0 2rpx 0 rgba(0, 0, 0, 0.1); //阴影
backdrop-filter: blur(20rpx); //模糊
.box {
display: flex;
flex-direction: column; //文本行排列顺序、堆叠的方向
align-items: center;
justify-content: center;
padding: 2rpx 12rpx;
.text {
font-size: 26rpx;
color: $text-font-color-2;
}
}
}
}
// 标题 退出x
.popHeader {
display: flex;
justify-content: space-between; //两端对齐
align-items: center;
.title {
color: $text-font-color-2;
font-size: 26rpx;
}
.close {
padding: 6rpx;
}
}
.infoPopup {
background: #fff;
padding: 30rpx;
border-radius: 30rpx 30rpx 0 0; //左右圆角
overflow: hidden; //超出隐藏
scroll-view {
max-height: 60vh; //最大高度
.content {
// 壁纸id
.row {
display: flex;
padding: 16rpx 0;
font-size: 32rpx;
line-height: 1.7em; //行间距
// 文字(不可选中
.label {
color: $text-font-color-3;
width: 140rpx;
text-align: right;
font-size: 30rpx;
}
// 数据(可选
.value {
flex: 1;
width: 0;
}
.roteBox {
display: flex; //显示一行
align-items: center; //垂直居中
//文字分数
.score {
font-size: 26rpx;
color: $text-font-color-2;
padding-left: 10rpx;
}
}
// 标签组
.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: 1em;
margin: 0 10rpx 10rpx 0;
}
}
.class {
color: $brand-theme-color;
}
}
.copyright {
font-size: 28rpx;
padding: 20rpx;
background: #F6F6F6;
color: #666;
border-radius: 10rpx;
margin: 20rpx 0;
line-height: 1.6em;
}
}
}
}
.scorePopup {
background: #fff;
padding: 30rpx;
width: 70vw;
border-radius: 30rpx; //圆角
// 内容
.content {
padding: 30rpx 0;
display: flex; //居中
justify-content: center;
align-items: center;
.text {
color: #FFCA3E;
padding-left: 10rpx;
width: 80rpx;
line-height: 1em;
text-align: right; //右对齐
font-size: 28rpx;
}
}
.footer {
padding: 10rpx 0;
display: flex;
align-items: center;
justify-content: center;
}
}
}
</style>
34. onShareAppMessage分享好友和分享微信朋友圈
onShareAppMessage(OBJECT) 分享 | uni-app官网
此事件需要 return 一个 Object,用于自定义分享内容,其内容如下:
参数名 | 类型 | 必填 | 说明 | 平台差异说明 |
---|---|---|---|---|
title | String | 是 | 分享标题 | |
path | String | 是 | 页面 path ,必须是以 / 开头的完整路径。注意:京东小程序,开头不要加'/' | QQ小程序不支持 |
index.vue
<script setup>
import {
onShareAppMessage
} from "@dcloudio/uni-app"
//分享给好友
onShareAppMessage((e) => {
return {
title: "壁纸,好看的手机壁纸",
path: "/pages/classify/classify"
}
})
</script>
wx.onShareTimeline(function listener) 转发 / wx.onShareTimeline
onShareTimeline | 监听用户点击右上角转发到朋友圈 | 微信小程序 | 2.8.1+ |
<script setup>
import {
onShareAppMessage,
onShareTimeline
} from "@dcloudio/uni-app"
//分享给好友
onShareAppMessage((e) => {
return {
title: "壁纸,好看的手机壁纸",
path: "/pages/classify/classify"
}
})
//分享朋友圈
onShareTimeline(() => {
return {
title: "壁纸,好看的手机壁纸"
}
})
</script>
微信小程序配置了onShareTimeline分享到朋友圈,但是在开发者工具中这里始终是灰色的,在真机调试的时候也没有发现有分享到朋友圈的相关信息。-CSDN博客
35.对分享页面传参进行处理
<script setup>
import {
ref
} from 'vue';
import {
apiGetClassList
} from "@/api/apis.js"
import {
onLoad,
onReachBottom,
onUnload,
onShareAppMessage,
onShareTimeline
} from "@dcloudio/uni-app"
//分类列表数据
const classList = ref([]);
const noData = ref(false)
//定义data参数
const queryParams = {
// 默认第一页
pageNum: 1,
// 默认一页12个
pageSize: 12
}
let pageName;
//获取id
onLoad((e) => {
// 解构对象
let {
id = null, name = null, type = null
} = e;
if (type) queryParams.type = type;
// 赋值
if (id) queryParams.classid = id;
pageName = name
//修改导航标题
uni.setNavigationBarTitle({
title: name
})
//执行获取分类列表方法,在onLoad中执行,不会忽略onLoad
getClassList();
})
// 触底加载
onReachBottom(() => {
// 判断noData
if (noData.value) return;
// 下一页
queryParams.pageNum++;
getClassList();
})
onUnload(() => {
uni.removeStorageSync("storgClassList")
})
//获取分类列表网络数据
const getClassList = async () => {
let res;
if (queryParams.classid) res = await apiGetClassList(queryParams);
// 新数据+老数据
classList.value = [...classList.value, ...res.data];
// 判断数据是否小于固定值
if (queryParams.pageSize > res.data.length) noData.value = true;
uni.setStorageSync("storgClassList", classList.value);
}
//分享给好友
onShareAppMessage((e) => {
return {
title: "壁纸-" + pageName,
//需要传递ID
path: "/pages/classlist/classlist?id=" + queryParams.classid + "&name=" + pageName
}
})
//分享朋友圈
onShareTimeline(() => {
return {
title: "壁纸-" + pageName,
query: "id=" + queryParams.classid + "&name=" + pageName
}
})
</script>
<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?'noMore':'loading'"></uni-load-more>
</view>
<view class="safe-area-inset-bottom"></view>
</view>
</template>
<style lang="scss" scoped>
.classlist {
.content {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 5rpx;
padding: 5rpx;
.item {
height: 440rpx;
image {
width: 100%;
height: 100%;
display: block;
}
}
}
}
</style>
/pages/preview/preview
<script setup>
import {
ref
} from 'vue';
import {
onLoad,
onShareAppMessage,
onShareTimeline
} from "@dcloudio/uni-app"
import {
getStatusBarHeight
} from "../../utils/system.js"
import {
apiGetSetupScore,
apiWriteDownload,
apiDetailWall
} from "@/api/apis.js"
const maskState = ref(true);
// 弹窗状态
const infoPopup = ref(null);
const scorePopup = ref(null);
const userScore = ref(0)
const classList = ref([]);
// 当前的ID
const currentId = ref(null);
const currentIndex = ref(0)
// 壁纸信息,设为空对象,不会报错
const currentInfo = ref({});
// 数组存储浏览过的壁纸
const readImgs = ref([]);
// 评分状态,默认未评分
const isScore = ref(false);
//点击info弹窗
const clickInfo = () => {
infoPopup.value.open();
}
//点击关闭信息弹窗
const clickInfoClose = () => {
infoPopup.value.close();
}
//评分弹窗
const clickScore = () => {
// 判断是否存在userScore
if (currentInfo.value.userScore) {
// 改变评分状态
isScore.value = true;
// userScore的值变成数据库的值
userScore.value = currentInfo.value.userScore;
}
scorePopup.value.open();
}
//关闭评分框
const clickScoreClose = () => {
scorePopup.value.close();
// 初始化
userScore.value = 0;
// 评分状态
isScore.value = false;
}
//确认评分
const submitScore = async () => {
// 加载
uni.showLoading({
title: "加载中..."
})
// 解构
let {
classid,
_id: wallId
} = currentInfo.value;
// 调用接口,异步请求同步化
let res = await apiGetSetupScore({
classid,
wallId,
userScore: userScore.value
})
// 结束加载
uni.hideLoading();
//提示
if (res.errCode === 0) {
uni.showToast({
title: "评分成功",
icon: "none"
})
// 当前对象追加userScore
classList.value[currentIndex.value].userScore = userScore.value;
//缓存, 用于显示已评分的壁纸评分
uni.setStorageSync("storgClassList", classList.value);
// 评分成功调用关闭弹窗
clickScoreClose();
}
}
//遮罩层状态
const maskChange = () => {
maskState.value = !maskState.value
}
//返回上一页
const goBack = () => {
uni.navigateBack()
}
//获取缓存
const storgClassList = uni.getStorageSync("storgClassList") || [];
classList.value = storgClassList.map(item => {
return {
...item,
picurl: item.smallPicurl.replace("_small.webp", ".jpg")
}
})
onLoad(async (e) => {
// 赋值
currentId.value = e.id;
if (e.type == 'share') {
let res = await apiDetailWall({id: currentId.value});
classList.value = res.data.map(item => {
return {
...item,
picurl: item.smallPicurl.replace("_small.webp", ".jpg")
}
})
}
// findIndex比较每一个_id与传入的id相等
currentIndex.value = classList.value.findIndex(item => item._id == currentId.value)
//赋值 壁纸信息,根据索引值
currentInfo.value = classList.value[currentIndex.value]
// 把浏览过的壁纸索引推入
readImgsFun();
})
const swiperChange = (e) => {
// 赋值索引值
currentIndex.value = e.detail.current;
//赋值 壁纸信息,根据索引值
currentInfo.value = classList.value[currentIndex.value]
// 把滑动过的壁纸索引推入
readImgsFun();
console.log(e);
}
console.log(classList.value);
//点击下载
const clickDownload = async () => {
// #ifdef H5
uni.showModal({
content: "请长按保存壁纸",
showCancel: false
})
// #endif
// 除了H5,都适用uni.saveImageToPhotosAlbum(OBJECT)
// #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: "需要授权保存相册",
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: "壁纸",
// "&type=share"读数据
path: "/pages/preview/preview?id=" + currentId.value + "&type=share"
}
})
//分享朋友圈
onShareTimeline(() => {
return {
title: "壁纸",
query: "id=" + currentId.value + "&type=share"
}
})
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)];
}
</script>
<template>
<view class="preview" v-if="currentInfo">
<!-- 轮播图 -->
<swiper circular :current="currentIndex" @change="swiperChange">
<swiper-item v-for="(item,index) in classList" :key="item._id">
<image v-if="readImgs.includes(index)" @click="maskChange" :src="item.picurl" mode="aspectFill"></image>
</swiper-item>
</swiper>
<!-- 遮罩层 -->
<view class="mask" v-if="maskState">
<!-- 返回按钮 -->
<!-- #ifndef MP-TOUTIAO -->
<view class="goBack" @click="goBack" :style="{top:getStatusBarHeight()+'px'}">
<uni-icons type="back" color="#fff" size="20"></uni-icons>
</view>
<!-- #endif -->
<!-- 显示进度 动态数据-->
<view class="count">{{currentIndex+1}} / {{classList.length}}</view>
<!-- 时间-->
<view class="time">
<uni-dateformat :date="new Date()" format="hh:mm"></uni-dateformat>
</view>
<!-- 日期 -->
<view class="date">
<uni-dateformat :date="new Date()" format="MM月dd日"></uni-dateformat>
</view>
<!-- 功能按钮 -->
<view class="footer">
<view class="box" @click="clickInfo">
<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="23"></uni-icons>
<view class="text">下载</view>
</view>
</view>
</view>
<uni-popup ref="infoPopup" type="bottom">
<view class="infoPopup">
<!-- 标题 退出x -->
<view class="popHeader">
<view></view>
<view class="title">壁纸信息</view>
<view class="close" @click="clickInfoClose">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<!-- 滚动条 -->
<scroll-view scroll-y>
<view class="content">
<view class="row">
<view class="label">壁纸ID:</view>
<text selectable class="value">{{currentInfo._id}}</text>
</view>
<!-- <view class="row">
<view class="label">分类:</view>
<text class="value class">明星美女</text>
</view> -->
<view class="row">
<view class="label">发布者:</view>
<text class="value">{{currentInfo.nickname}}</text>
</view>
<view class="row">
<text class="label">评分:</text>
<view class='value roteBox'>
<uni-rate readonly touchable value="4" size="16" />
<text class="score">{{currentInfo.score}}分</text>
</view>
</view>
<view class="row">
<text class="label">摘要:</text>
<view class='value'>
{{currentInfo.description}}
</view>
</view>
<view class="row">
<text class="label">标签:</text>
<view class='value tabs'>
<view class="tab" v-for="tab in currentInfo.tabs" :key="tab">
{{tab}}
</view>
</view>
</view>
<view class="copyright">声明:XXXXXXXXXXX</view>
</view>
</scroll-view>
</view>
</uni-popup>
<uni-popup ref="scorePopup" :is-mask-click="false">
<view class="scorePopup">
<view class="popHeader">
<view></view>
<view class="title">{{isScore?'评分过了~':'壁纸评分'}}</view>
<view class="close" @click="clickScoreClose()">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
<!-- 内容 -->
<view class="content">
<uni-rate v-model="userScore" allowHalf :disabled="isScore" disabled-color="#FFCA3E" />
<text class="text">{{userScore}}分</text>
</view>
<!-- 按钮 -->
<view class="footer">
<button @click="submitScore" :disabled="!userScore || isScore" type="default" size="mini"
plain>确认评分</button>
</view>
</view>
</uni-popup>
</view>
</template>
<style lang="scss" scoped>
.preview {
width: 100%;
height: 100vh;
position: relative;
swiper {
width: 100%;
height: 100%;
image {
width: 100%;
height: 100%;
}
}
// 信息
.mask {
&>view {
//让mask紧邻的view
position: absolute;
left: 0;
margin: auto;
color: #fff;
right: 0;
width: fit-content; //内容决定宽度
}
.goBack {
width: 38px;
height: 38px;
background: rgba(0, 0, 0, 0.5);
left: 30rpx;
margin-left: 0;
border-radius: 100px;
top: 0;
backdrop-filter: blur(10rpx);
border: 1rpx solid rgba(255, 255, 255, 0.3);
// 图标居中
display: flex;
align-items: center;
justify-content: center;
}
.count {
top: 10vh;
background: rgba(0, 0, 0, 0.3); //背景
font-size: 28rpx; //字号
border-radius: 40rpx; //圆角
padding: 8rpx 28rpx; //上下8 左右28
backdrop-filter: blur(10rpx); //模糊
}
.time {
font-size: 140rpx; //字体大小
top: calc(10vh + 80rpx); //计算函数
font-weight: 100; //字体加粗
line-height: 1em; //行高
text-shadow: 0 4rpx rgba(0, 0, 0, 0.3); //文字阴影
}
.date {
font-size: 34rpx;
top: calc(10vh + 230rpx);
text-shadow: 0 2rpx rgba(0, 0, 0, 0.3);
}
.footer {
background: rgba(255, 255, 255, 0.8);
bottom: 10vh; //以底为基准
width: 65vw;
height: 120rpx;
border-radius: 120rpx; //圆角
color: #000;
display: flex; //一行
justify-content: space-around; //两端对齐
align-items: center;
box-shadow: 0 2rpx 0 rgba(0, 0, 0, 0.1); //阴影
backdrop-filter: blur(20rpx); //模糊
.box {
display: flex;
flex-direction: column; //文本行排列顺序、堆叠的方向
align-items: center;
justify-content: center;
padding: 2rpx 12rpx;
.text {
font-size: 26rpx;
color: $text-font-color-2;
}
}
}
}
// 标题 退出x
.popHeader {
display: flex;
justify-content: space-between; //两端对齐
align-items: center;
.title {
color: $text-font-color-2;
font-size: 26rpx;
}
.close {
padding: 6rpx;
}
}
.infoPopup {
background: #fff;
padding: 30rpx;
border-radius: 30rpx 30rpx 0 0; //左右圆角
overflow: hidden; //超出隐藏
scroll-view {
max-height: 60vh; //最大高度
.content {
// 壁纸id
.row {
display: flex;
padding: 16rpx 0;
font-size: 32rpx;
line-height: 1.7em; //行间距
// 文字(不可选中
.label {
color: $text-font-color-3;
width: 140rpx;
text-align: right;
font-size: 30rpx;
}
// 数据(可选
.value {
flex: 1;
width: 0;
}
.roteBox {
display: flex; //显示一行
align-items: center; //垂直居中
//文字分数
.score {
font-size: 26rpx;
color: $text-font-color-2;
padding-left: 10rpx;
}
}
// 标签组
.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: 1em;
margin: 0 10rpx 10rpx 0;
}
}
.class {
color: $brand-theme-color;
}
}
.copyright {
font-size: 28rpx;
padding: 20rpx;
background: #F6F6F6;
color: #666;
border-radius: 10rpx;
margin: 20rpx 0;
line-height: 1.6em;
}
}
}
}
.scorePopup {
background: #fff;
padding: 30rpx;
width: 70vw;
border-radius: 30rpx; //圆角
// 内容
.content {
padding: 30rpx 0;
display: flex; //居中
justify-content: center;
align-items: center;
.text {
color: #FFCA3E;
padding-left: 10rpx;
width: 80rpx;
line-height: 1em;
text-align: right; //右对齐
font-size: 28rpx;
}
}
.footer {
padding: 10rpx 0;
display: flex;
align-items: center;
justify-content: center;
}
}
}
</style>
出现的问题待解决
1.下载壁纸,一直loading(已)
2. 分享朋友圈为灰色(已)
解决方法
3. 请使用“user-select”代替。“<text>”的“selectable”属性已不再使用(未)
/pages/preview/preview
<view class="row">
<view class="label">壁纸ID:</view>
<text selectable class="value">{{currentInfo._id}}</text>
</view>