1.使用 uni.previewImage() 预览图片
1.1 图片列表
1.2 预览
1.2.1 样式无法调整
1.2.2 微信小程序不支持预览本地文件路径图片(图片上传到小程序的临时文件存储或云服务存储)
1.3 无法绑定 @longpress="saveImage(item)" 长按保存图片事件
1.4 前端代码
<template><view class="container"><view class="tabs"><uni-segmented-control:current="current":values="tabList"@clickItem="onClickItem"styleType="button"activeColor="#27BA9B"/></view><view class="content"><view v-show="current === 0"><view class="video"><videostyle="width: 100%;"src="https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/2minute-demo.mp4"enable-play-gesturev-for="item in 3"/></view></view><view v-show="current === 1"><scroll-view><view class="image-box" v-for="(item,index) in images"><view class="navigator" ><!-- @tap:点击事件, @longpress:长按事件 --><image class="image" :src="item" @tap="previewImage(index)" @longpress="saveImage(item)" /></view></view></scroll-view></view><view v-show="current === 2"><scroll-view><uni-card v-for="item in 10"><text>这是一个基础卡片示例,内容较少,此示例展示了一个没有任何属性不带阴影的卡片。</text></uni-card></scroll-view></view></view></view>
</template><script setup>import { ref,computed } from 'vue'const tabList=['视频', '图片', '文案']// 选中tab的下标const current = ref(0)// 选中的图片indexconst activeIndex = ref(0)// 切换tabconst onClickItem= (e)=>{current.value = e.currentIndex}// 图片列表// 微信小程序 uni.previewImage() 不支持使用本地文件路径预览图片,可上传到小程序的临时文件存储或云服务存储const images = ref(["https://ww2.sinaimg.cn/mw690/008a4fzDgy1hrc5rdztg7j30zk24ykfc.jpg", // 云服务存储"https://ww4.sinaimg.cn/mw690/005QiJkMgy1hrpsfxno4rj30zu25odq0.jpg", // 云服务存储"https://wx1.sinaimg.cn/mw690/005UJ76vgy1hrh4zt0k1ij30v91votw9.jpg", // 云服务存储"https://wx1.sinaimg.cn/mw690/60ed0cf7ly1hs8msnz6e6j20zu25o16d.jpg", // 云服务存储"/static/images/beauty1.jpg", // 本地文件存储])// uni.previewImage() 图片预览const previewImage= (index)=>{uni.previewImage({urls: images.value,current: images.value[index], // 当前显示图片的链接});}// 保存图片const saveImage= async(url)=> {try {let filePath;if (url.startsWith('/')) {filePath = url; // 本地图片路径,可直接保存} else {const result = await uni.downloadFile({ url }); // 云服务图片地址,要先下载filePath = result.tempFilePath;}await uni.saveImageToPhotosAlbum({ filePath });uni.showToast({ title: '保存成功', icon: 'success', duration: 2000 });} catch (err) {console.error('保存失败:', err);}}
</script><style lang="less" scoped>
.container{display: flex;flex-direction: column;height: 100vh;background-color: #fff;.tabs{padding: 10px;}.content{flex: 1;overflow-y: auto;.video{margin: 10px;}.image-box{display: inline-flex; // 使用 flex 布局,并且作为行内元素margin: 0 5px;width: 30%;.navigator{display: flex;width: 100%;}}}
}
</style>
2.使用自定义组件预览图片
2.1 图片列表
2.2 预览(可预览云服务存储和本地存储的图片)
2.3 长按保存
2.4 前端代码
2.4.1 自定义预览组件<Preview />
<!-- 图片预览组件 -->
<template><view class="container"><view class="fullscreen" ><swiper class="fullscreen-swiper" :current="activeIndexValue" @change="handleSwiperChange" circular><swiper-item class="swiper-item" v-for="(item, index) in imageListValue" :key="index"><image :src="item" @longpress="saveImage(item)" mode="scaleToFill" style="width: 100vw; height: 100vh;" /></swiper-item></swiper><view class="number">{{ activeIndexValue+1 }}/{{ imageListValue.length }}</view><button class="btn" type="default" @tap="emit('close')">退出全屏</button></view></view>
</template><script setup>import { ref, onMounted } from 'vue';import { onLoad } from '@dcloudio/uni-app'// 子调父,退出预览模式const emit = defineEmits()// 获取父组件的参数,activeIndex:选中的索引,imageList:图片url列表let query = defineProps(["activeIndex","imageList"])let activeIndexValue = ref(query.activeIndex)let imageListValue = ref(query.imageList)// 要保存图片的urlconst url = ref('');// 获取屏幕边界到安全区域距离const { safeAreaInsets } = uni.getSystemInfoSync()// 处理 swiper change 事件const handleSwiperChange = (event) => {activeIndexValue.value = event.detail.current;url.value = imageListValue.value[activeIndexValue.value];};// 保存图片const saveImage= async(url)=> {try {let filePath;if (url.startsWith('/')) {filePath = url; // 本地图片路径,可直接保存} else {const result = await uni.downloadFile({ url }); // 云服务图片地址,要先下载filePath = result.tempFilePath;}await uni.saveImageToPhotosAlbum({ filePath });uni.showToast({ title: '保存成功', icon: 'success', duration: 2000 });} catch (err) {console.error('保存失败:', err);}}
</script><style lang="less" scoped>
.container {display: flex;justify-content: center;align-items: center;height: 100vh;background-color: #f4f4f4;
}.swiper {height: 100%;width: 100%;border: 1px solid #ccc;overflow: hidden;
}.swiper-item {height: 100%;display: flex;justify-content: center;align-items: center;
}.fullscreen {position: fixed;top: 0;left: 0;width: 100vw;height: 100vh;display: flex;justify-content: center;align-items: center;z-index: 1000;background-color: rgba(0, 0, 0, 0.8);
}.fullscreen-swiper {width: 100%;height: 100%;
}.number{position: absolute;top: 20px;left: 50%;transform: translateX(-50%);color: #fff;background-color: rgba(0, 0, 0, 0.2);padding: 5px 10px;border-radius: 20px;
}.btn {position: absolute;bottom: 20px;left: 50%;transform: translateX(-50%);color: #ccc;background-color: rgba(0, 0, 0, 0.2);
}
</style>
2.4.2 使用自定义预览组件<Preview />
<template><view class="container"><view class="tabs"><uni-segmented-control:current="current":values="tabList"@clickItem="onClickItem"styleType="button"activeColor="#27BA9B"/></view><view class="content"><view v-show="current === 0"><view class="video"><videostyle="width: 100%;"src="https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/2minute-demo.mp4"enable-play-gesturev-for="item in 3"/></view></view><view v-show="current === 1"><scroll-view><view class="image-box" v-for="(item,index) in images"><!-- @tap:点击事件, @longpress:长按事件 --><view class="navigator" @tap="preview(index)" ><image class="image" :src="item" @longpress="saveImage(item)" /></view></view></scroll-view></view><view v-show="current === 2"><scroll-view><uni-card v-for="item in 10"><text>这是一个基础卡片示例,内容较少,此示例展示了一个没有任何属性不带阴影的卡片。</text></uni-card></scroll-view></view></view></view><!-- 自定义预览组件 --><Preview class="container" v-if="previewFlag" :activeIndex="activeIndex" :imageList="images" @close="close" />
</template><script setup>import { ref,computed } from 'vue'const tabList=['视频', '图片', '文案']// 选中tab的下标const current = ref(0)// 是否是预览模式let previewFlag = ref(false);// 选中的图片indexconst activeIndex = ref(0)// 子组件调用父组件的关闭预览const close = ()=>{previewFlag.value = false}// 点击开启预览模式const preview= (index)=>{previewFlag.value = trueactiveIndex.value = index}// 切换tabconst onClickItem= (e)=>{current.value = e.currentIndex}// 图片列表// 微信小程序 uni.previewImage() 不支持使用本地文件路径预览图片,可上传到小程序的临时文件存储或云服务存储const images = ref(["https://ww2.sinaimg.cn/mw690/008a4fzDgy1hrc5rdztg7j30zk24ykfc.jpg", // 云服务存储"https://ww4.sinaimg.cn/mw690/005QiJkMgy1hrpsfxno4rj30zu25odq0.jpg", // 云服务存储"https://wx1.sinaimg.cn/mw690/005UJ76vgy1hrh4zt0k1ij30v91votw9.jpg", // 云服务存储"https://wx1.sinaimg.cn/mw690/60ed0cf7ly1hs8msnz6e6j20zu25o16d.jpg", // 云服务存储"/static/images/beauty1.jpg", // 本地文件存储])// 保存图片const saveImage= async(url)=> {try {let filePath;if (url.startsWith('/')) {filePath = url; // 本地图片路径,可直接保存} else {const result = await uni.downloadFile({ url }); // 云服务图片地址,要先下载filePath = result.tempFilePath;}await uni.saveImageToPhotosAlbum({ filePath });uni.showToast({ title: '保存成功', icon: 'success', duration: 2000 });} catch (err) {console.error('保存失败:', err);}}
</script><style lang="less" scoped>
.container{display: flex;flex-direction: column;height: 100vh;background-color: #fff;.tabs{padding: 10px;}.content{flex: 1;overflow-y: auto;.video{margin: 10px;}.image-box{display: inline-flex; // 使用 flex 布局,并且作为行内元素margin: 0 5px;width: 30%;.navigator{display: flex;width: 100%;}}}
}
</style>