uni-app 开发微信小程序,实现图片预览和保存

news2024/10/25 11:42:23

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">
					<video
						style="width: 100%;"
						src="https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/2minute-demo.mp4"
						enable-play-gesture
						v-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)
	
	// 选中的图片index
	const activeIndex = ref(0)

	// 切换tab
	const 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= (url)=> {
		// 确认框
		uni.showModal({
			content: '下载该图片?',
			confirmColor: '#27BA9B',
			success: async(res) => {
				if (res.confirm) {
					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)
	
	// 要保存图片的url
	const url = ref('');

	// 获取屏幕边界到安全区域距离
	const { safeAreaInsets } = uni.getSystemInfoSync()

	// 处理 swiper change 事件
	const handleSwiperChange = (event) => {
		activeIndexValue.value = event.detail.current;
		url.value = imageListValue.value[activeIndexValue.value];
	};

	// 保存图片
	const saveImage= (url)=> {
		// 确认框
		uni.showModal({
			content: '下载该图片?',
			confirmColor: '#27BA9B',
			success: async(res) => {
				if (res.confirm) {
					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">
					<video
						style="width: 100%;"
						src="https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/2minute-demo.mp4"
						enable-play-gesture
						v-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);
	
	// 选中的图片index
	const activeIndex = ref(0)
	
	// 子组件调用父组件的关闭预览
	const close = ()=>{
		previewFlag.value = false
	}
	
	// 点击开启预览模式
	const preview= (index)=>{
		previewFlag.value = true
		activeIndex.value = index
	}
	
	// 切换tab
	const 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= (url)=> {
		// 确认框
		uni.showModal({
			content: '下载该图片?',
			confirmColor: '#27BA9B',
			success: async(res) => {
				if (res.confirm) {
					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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2223248.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++,STL 044(24.10.24)

内容 1.set容器的构造函数。 2.set容器的赋值操作。 运行代码 #include <iostream> #include <set>using namespace std;void printSet(set<int> &s) {for (set<int>::iterator it s.begin(); it ! s.end(); it){cout << *it << &…

充电宝目前什么牌子的质量好耐用?盘点2024年五款高性价充电宝!

充电宝目前什么牌子的质量好耐用&#xff1f;这是许多人在选购充电宝时最为关心的问题。随着移动设备的普及和技术的进步&#xff0c;充电宝已经成为日常生活中不可或缺的伴侣。为了帮助大家在众多品牌中做出明智的选择&#xff0c;我特地盘点了2024年五款具有高性价比的充电宝…

跨境科技公司如何借助 NocoBase 升级内部系统并实现外部业务增长?

关于政元软件 深圳市政元软件有限公司&#xff0c;作为国家级高新技术企业和专精特新企业&#xff0c;自 2006 年成立以来&#xff0c;一直走在跨境企业服务的前沿。近年来&#xff0c;政元软件将人工智能技术与跨境业务场景结合&#xff0c;为客户提供创新的解决方案&#xff…

数据结构——树、二叉树和森林间的转换

前言 介绍 &#x1f343;数据结构专区&#xff1a;数据结构 参考 该部分知识参考于《数据结构&#xff08;C语言版 第2版&#xff09;》129~130页 &#x1f308;每一个清晨&#xff0c;都是世界对你说的最温柔的早安&#xff1a;ૢ(≧▽≦)و✨ 目录 前言 1、基础知识 2…

现场总是发生急停,很可能是PLC和设置间网络中断

如果你的现场总是发生急停&#xff0c;很可能是PLC和设置间网络中断&#xff0c;本文用一个真实案例告诉你问题背后的原因和解决方法&#xff01; 这是一台生产汽车配件的机器&#xff0c;使用1500F的控制器连接机器人控制器&#xff0c;现场装置总会莫名其妙的发生急停故障。…

Linux运维_搭建smb服务

Samba&#xff08;SMB&#xff09;是一个开源软件&#xff0c;允许Linux和Unix系统与Windows系统共享文件和打印机。以下是一些关于Samba和SMB的基本信息和操作步骤&#xff1a; Samba 和 SMB 基本概念 Samba&#xff1a;实现了SMB&#xff08;Server Message Block&#xff…

程序员中后期,靠什么和其他人拉开差距?

有人说程序员是吃青春饭的&#xff0c;到了35岁会被淘汰。但和身边几十位程序员聊完后&#xff0c;发现实际情况不尽如此&#xff01; 工作两三年的时候&#xff0c;有些程序员技术优势明显&#xff0c;看起来职业前途很好&#xff1b;工作四五年后&#xff0c;该学的技术都熟…

Vue学习记录之十七 css中样式穿透及新特征介绍

一、scoped原理 在vue页面的css中,有一个设置为scoped,使用以后dom的节点会出现下面的规则。其实我们打完包就是一个html页面,如果不做处理,将会导致css混乱。 给HTML的DOM节点加一个不重复data属性(形如:data-v-123)来表示他的唯一性在每句css选择器的末尾(编译后的生成的…

Java每日面试题(前端Vue拓展)(day20)

目录 Vue是什么&#xff1f;v-if 和 v-show的区别&#xff1f;watch与compute的区别&#xff1f;使用过哪些前端组件&#xff1f;Vue父子组件如何进行交互&#xff1f;Vue的生命周期v-for指令中的key属性有什么用&#xff1f; Vue是什么&#xff1f; Vue是一个渐进式 JavaScrip…

平时实战知识(混合版)map.keyset+stream+maven打包

为这个博主点赞!!!!!!!!!!!!!!!! Java stream 使用样例_哪些类可以使用stream-CSDN博客 IDEA使用maven命令打包_idea 打包maven-CSDN博客

博客搭建之路:hexo搜索引擎收录

文章目录 hexo搜索引擎收录以百度为例 hexo搜索引擎收录 hexo版本5.0.2 npm版本6.14.7 next版本7.8.0 写博客的目的肯定不是就只有自己能看到&#xff0c;想让更多的人看到就需要可以让搜索引擎来收录对应的文章。hexo支持生成站点地图sitemap 在hexo下的_config.yml中配置站点…

【D3.js in Action 3 精译_035】4.1 D3 中的坐标轴的创建(下篇):坐标轴与轴标签的具体实现

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可…

uniapp使用navigator标签不支持flex布局

前言 今天使用uniapp开发时&#xff0c;选用navigator作为flex布局容器&#xff0c;内部元素水平排列&#xff0c;可是发现微信小程序生效&#xff0c;网页端不生效。 微信小程序效果如下&#xff1a; 网页端效果如下&#xff1a; 源代码如下&#xff1a; <template>&l…

园区高能耗企业 水-电-气-热-油采集系统-能源管理系统

能源管理系统能源管理系统源码能源管理平台能源管理系统&#xff08;EMS&#xff09;能源监测能源管控能源系统能源监控能源预测&#xff0c;适用于高能耗企业能源企业 一、介绍 基于SpringCloud的能管管理系统-能源管理平台源码-能源在线监测平台-双碳平台源码-SpringCloud全…

Vxe UI vue vxe-table 虚拟树表格的使用,流畅的渲染万级数据树结构表格

Vxe UI vue vxe-table 虚拟树表格的使用&#xff0c;流畅的渲染万级数据树结构表格 代码 普通树表格&#xff0c;一般存数据库里都是平级数据&#xff0c;vxe-table 的树渲染这就非常友好了&#xff0c;只有带有父子id关联的数组&#xff0c;就可以自动渲染树表格。 <te…

LeetCode--买卖股票的最佳时机含冷冻期--动态规划

一、题目解析 二、算法原理 我们可以使用dp[i]来表示第i天买卖股票所获得的最大利润。由题可得我们只能持有一支股票&#xff0c;并且在卖出后有冷冻期的限制&#xff0c;因此我们会有三种不同的状态&#xff1a; 我们目前持有一支股票&#xff0c;对应的「累计最大收益」记为…

ONLYOFFICE 文档8.2版本已发布:PDF 协作编辑、改进界面、性能优化等更新

ONLYOFFICE 在线编辑器最新版本已经发布&#xff0c;其中包含30多个新功能和500多个错误修复。阅读本文了解所有更新。 关于 ONLYOFFICE 文档 ONLYOFFICE 是一个开源项目&#xff0c;专注于高级和安全的文档处理。坐拥全球超过 1500 万用户&#xff0c;ONLYOFFICE 是在线办公领…

基于Java+SpringBoot+Vue的水果购物网站的设计与实现

基于JavaSpringBootVue的水果购物网站的设计与实现 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1…

【C++基础编程】一、初识C++

文章目录 1、编程语言是什么2、进制3、第一个C程序4、注释 一、初识C 1、编程语言是什么 我们编写程序&#xff0c;就是希望与计算机进行交流&#xff0c;让计算机帮助我们实现我们期望的效果。从这点出发&#xff0c;其实和人与人之间的沟通交流是一样的。两个人如果需要正常…

8.MySQL复合查询

目录 复合查询基本查询回顾多表查询 - 笛卡尔积自连接子查询单行子查询多行子查询多列子查询在from中使用子查询 合并查询unionunion all 表的内连和外连内连接外连接左外连接右外连接 复合查询 前面我们讲解的mysql表的查询都是对一张表进行查询&#xff0c;在实际开发中这远远…