基于 UniApp 的壁纸预览与分类浏览应用实现
·
在移动应用开发中,壁纸类应用的核心体验体现在三个方面:流畅的图片浏览、高效的分类体系和便捷的交互操作。本文将结合实际代码,详细解析基于 UniApp 开发的壁纸应用核心功能实现,包括分页加载、图片预览、滑动切换和弹窗交互等关键模块。
一、分类列表与分页加载功能
壁纸应用的基础是高效展示大量图片资源,分页加载是实现这一目标的核心技术。
1. 核心实现思路
- 采用 "页码 + 页大小" 的分页参数控制数据加载
- 监听页面滚动到底部事件触发下一页加载
- 本地缓存已加载数据,提升页面切换体验
- 通过状态标识控制加载状态(加载中 / 无更多)
2. 代码实现
列表页(classlist.vue)完整逻辑:
<template>
<view class="classlist">
<!-- 初始加载状态 -->
<view class="loadingLayout" v-if="!classList.length && !noDate">
<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 || noDate">
<uni-load-more :status="noDate ? 'noMore' : 'loading'"></uni-load-more>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad, onReachBottom } from '@dcloudio/uni-app'
import { APIgetClassList } from '@/api/apis.js'
// 列表数据存储
const classList = ref([])
// 分页参数
const queryParams = {
pageNum: 1, // 当前页码
pageSize: 9, // 每页条数
classid: '' // 分类ID(从路由获取)
}
// 是否无更多数据
const noDate = ref(false)
// 获取列表数据
const getClassList = async () => {
const res = await APIgetClassList(queryParams)
// 拼接新数据(而非覆盖)
classList.value = [...classList.value, ...res.data.data]
// 判断是否还有更多数据
if (res.data.data.length < queryParams.pageSize) {
noDate.value = true
}
// 缓存数据到本地,供预览页使用
uni.setStorageSync("strogClassList", classList.value)
}
// 页面加载时初始化
onLoad((e) => {
// 从路由参数获取分类ID和名称
const { id, name } = e
queryParams.classid = id
// 设置导航栏标题
uni.setNavigationBarTitle({ title: name })
// 加载第一页数据
getClassList()
})
// 监听页面滚动到底部
onReachBottom(() => {
// 如果已无更多数据,停止加载
if (noDate.value) return
// 页码自增,加载下一页
queryParams.pageNum++
getClassList()
})
</script>
<style lang="scss">
.content {
display: grid;
grid-template-columns: repeat(3, 1fr); // 3列网格布局
gap: 10rpx;
.item {
height: 440rpx;
image {
width: 100%;
height: 100%;
display: block;
}
}
}
</style>
3. 技术亮点
- 网格布局:使用
grid-template-columns: repeat(3, 1fr)实现自适应三列布局,无需手动计算宽度 - 数据缓存:通过
uni.setStorageSync将列表数据缓存到本地,避免预览页重复请求 - 状态管理:使用
noDate标识控制加载状态,防止无效请求 - 路由传参:通过
onLoad接收路由参数,实现分类与列表的关联
二、图片预览与滑动切换功能
预览页是壁纸应用的核心交互页面,需要实现流畅的大图浏览和切换体验。
1. 核心实现思路
- 从本地缓存获取图片列表,避免重复网络请求
- 实现图片地址转换(缩略图→高清图)
- 预加载相邻图片,提升滑动流畅度
- 支持循环滑动和索引同步
2. 代码实现
预览页(preview.vue)核心逻辑:
<template>
<view class="preview">
<!-- 图片轮播容器 -->
<swiper
:indicator-dots="true"
:autoplay="true"
:interval="3000"
:duration="1000"
:current="currentIndex"
@change="swiperChange"
circular <!-- 开启循环滑动 -->
>
<swiper-item v-for="(item, index) in ClassList" :key="item._id">
<!-- 只加载预加载列表中的图片 -->
<image
v-if="readImg.includes(index)"
:src="item.picurl"
mode="aspectFill"
@click="maskchange"
></image>
</swiper-item>
</swiper>
<!-- 计数器显示 -->
<view class="count" v-show="!ismask">
{{ currentIndex + 1 }} / {{ ClassList.length }}
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
// 从本地缓存获取列表数据
const strogClassList = uni.getStorageSync("strogClassList")
const ClassList = ref([])
// 当前图片索引
const currentIndex = ref(0)
// 需要预加载的图片索引列表
const readImg = ref([])
// 遮罩层显示状态
const ismask = ref(false)
// 初始化图片数据(转换为高清图)
ClassList.value = strogClassList.map(item => ({
...item,
// 替换缩略图地址为高清图地址
picurl: item.smallPicurl.replace("_small.webp", ".jpg")
}))
// 图片预加载逻辑
const readImgfun = () => {
// 计算需要预加载的索引(当前、上一张、下一张)
const prevIndex = currentIndex.value - 1 < 0
? ClassList.value.length - 1
: currentIndex.value - 1
const nextIndex = currentIndex.value + 1 >= ClassList.value.length
? 0
: currentIndex.value + 1
// 添加到预加载列表并去重
readImg.value = [...new Set([prevIndex, currentIndex.value, nextIndex])]
}
// 滑动切换事件
const swiperChange = (e) => {
currentIndex.value = e.detail.current
// 滑动后重新预加载
readImgfun()
}
// 页面加载时初始化
onLoad((e) => {
// 从路由获取当前图片ID
const { id } = e
// 找到当前图片在列表中的索引
currentIndex.value = ClassList.value.findIndex(item => item._id === id)
// 初始化预加载
readImgfun()
})
// 点击切换遮罩层显示
const maskchange = () => {
ismask.value = !ismask.value
}
</script>
3. 技术亮点
- 图片地址转换:通过
replace方法将缩略图地址转换为高清图,节省流量同时保证预览质量 - 预加载优化:只加载当前、上一张和下一张图片,避免一次性加载所有图片导致的内存占用过高
- 循环滑动处理:通过三元表达式处理边界索引(首图的上一张是尾图,尾图的下一张是首图)
- 按需加载:通过
v-if="readImg.includes(index)"控制图片加载时机,提升初始加载速度
三、弹窗交互(信息 / 评分)功能
弹窗是展示额外信息和接收用户输入的重要组件,在壁纸应用中用于展示壁纸详情和评分功能。
1. 核心实现思路
- 使用
uni-popup组件实现弹窗基础功能 - 区分底部弹窗(信息展示)和居中弹窗(评分交互)
- 通过
ref控制弹窗显示 / 隐藏 - 实现数据联动(当前壁纸信息与弹窗内容)
2. 代码实现
信息弹窗与评分弹窗实现:
<template>
<view class="preview">
<!-- 底部操作按钮 -->
<view class="footer" v-show="!ismask">
<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">评分</view>
</view>
</view>
<!-- 信息弹窗(底部弹出) -->
<uni-popup ref="infoPopup" type="bottom">
<view class="infoPopup">
<view class="popHeader">
<view class="title">壁纸信息</view>
<view class="close" @click="clickInfoclose">
<uni-icons type="closeempty" size="18"></uni-icons>
</view>
</view>
<scroll-view scroll-y>
<view class="content">
<view class="row">
<view class="lable">壁纸id:</view>
<text selectable class="value">{{ currentInfo._id }}</text>
</view>
<view class="row">
<view class="lable">发布者</view>
<text selectable class="value">{{ currentInfo.nickname }}</text>
</view>
<view class="row">
<view class="lable">评分</view>
<view class="value roteBox">
<uni-rate readonly v-model="currentInfo.score" />
<text class="score">{{ currentInfo.score }}分</text>
</view>
</view>
</view>
</scroll-view>
</view>
</uni-popup>
<!-- 评分弹窗(居中显示) -->
<uni-popup ref="scorePopup" :is-mask-click="false">
<view class="scorePopup">
<view class="popHeader">
<view class="title">壁纸评分</view>
<view class="close" @click="clickScoreclose">
<uni-icons type="closeempty" size="18"></uni-icons>
</view>
</view>
<view class="content">
<uni-rate v-model="userScore" allowHalf />
<text class="text">{{ userScore }}分</text>
</view>
<view class="footer">
<button @click="submitScore">确认评分</button>
</view>
</view>
</uni-popup>
</view>
</template>
<script setup>
import { ref, watch } from 'vue'
// 弹窗实例
const infoPopup = ref(null)
const scorePopup = ref(null)
// 当前壁纸信息
const currentInfo = ref({})
// 用户评分
const userScore = ref(0)
// 监听当前索引变化,更新当前壁纸信息
watch(currentIndex, (newVal) => {
currentInfo.value = ClassList.value[newVal]
})
// 信息弹窗控制
const clickInfo = () => {
infoPopup.value.open()
}
const clickInfoclose = () => {
infoPopup.value.close()
}
// 评分弹窗控制
const clickScore = () => {
// 打开弹窗时初始化评分(当前评分)
userScore.value = currentInfo.value.score
scorePopup.value.open()
}
const clickScoreclose = () => {
scorePopup.value.close()
}
// 提交评分
const submitScore = () => {
// 这里可以添加提交到后端的逻辑
uni.showToast({ title: `已评分:${userScore.value}分`, icon: 'none' })
scorePopup.value.close()
}
</script>
3. 技术亮点
- 弹窗类型区分:底部弹窗适合展示大量信息(带滚动),居中弹窗适合简单交互
- 数据联动:通过
watch监听当前索引变化,自动更新弹窗展示的壁纸信息 - 评分初始化:打开评分弹窗时自动填充当前评分,提升用户体验
- 交互细节:评分弹窗设置
is-mask-click="false",避免误触遮罩关闭弹窗
四、核心功能总结与扩展建议
关键技术点梳理
| 功能模块 | 核心技术 | 优化点 |
|---|---|---|
| 分页加载 | onReachBottom + 分页参数 | 本地缓存、加载状态控制 |
| 图片预览 | swiper + 图片预加载 | 地址转换、按需加载 |
| 弹窗交互 | uni-popup + ref | 类型区分、数据联动 |
扩展建议
- 图片下载功能:结合
uni.downloadFile和uni.saveImageToPhotosAlbum实现壁纸下载 - 收藏功能:添加本地存储或后端接口,实现壁纸收藏功能
- 分享功能:集成
uni.share实现壁纸分享到社交平台 - 预加载优化:根据网络状态动态调整预加载数量(WiFi 环境多加载,移动网络少加载)
通过以上实现,我们构建了一个功能完整、体验流畅的壁纸应用核心模块。UniApp 的跨平台特性和丰富的组件库,使得这些功能可以轻松运行在微信小程序、App 和 H5 等多个平台,大大提升了开发效率。
更多推荐


所有评论(0)