uniapp 自定义图片预览组件PicturePreview(Vue3、组合式、ts)

组件

html 复制代码
<template>
	<view class="preview-container" :style="{display: show ? 'block' : 'none'}">
		<view class="f-c-c close" @click="close">
			<YcSvgIcon name="close" width="15rpx" height="15rpx" color="#ffffff"></YcSvgIcon>
		</view>
		<swiper class="swiper" :indicator-dots="true" :autoplay="false" :interval="5000" :duration="500"
			:circular="true" @change="onSwiperChange" :current="currentIndex" @transition="scale = 1">
			<swiper-item v-for="(image, index) in images" :key="index">
				<movable-area scale-area class="movable-area">
					<movable-view class="movable-view" :scale="true" :scale-min="1" :scale-max="1" :scale-value="scale"
						@scale="onScale" out-of-bounds>
						<image class="preview-image" :src="image" mode="aspectFit" @click="close" />
					</movable-view>
				</movable-area>
			</swiper-item>
		</swiper>
	</view>
</template>

<script setup lang="ts">
	import { ref } from 'vue';

	const images = ref<Array<string>>([]);
	const currentIndex = ref(0);
	const show = ref(false);
	const scale = ref(1);

	function onSwiperChange(e : any) {
		scale.value = 1;
		currentIndex.value = e.detail.current;
	}
	const onScale = (e : any) => {
		scale.value = e.detail.scale;
		console.log(scale.value);
	}
	const close = () => {
		images.value = [];
		currentIndex.value = 0;
		show.value = false;
	}
	const previewImage = (imgs : Array<string>, index : number) => {
		images.value = imgs;
		currentIndex.value = index;
		show.value = true;
	}
	defineExpose({
		previewImage,
	})
</script>

<style scoped lang="scss">
	.preview-container {
		position: fixed;
		top: 0;
		left: 0;
		width: 100vw;
		height: 100vh;
		overflow: hidden;
		z-index: 99;
		background-color: rgba(0, 0, 0, 0.8);

		.close {
			position: absolute;
			top: 25rpx;
			right: 25rpx;
			z-index: 999;
		}

		.swiper {
			width: 100%;
			height: 100%;

			.movable-area {
				width: 100%;
				height: 100%;

				.movable-view {
					width: 100%;
					height: 100%;
				}
			}

			.preview-image {
				width: 100%;
				height: 100%;
			}
		}
	}
</style>

组件使用

html 复制代码
<template>
	<view class="photography-page view-container">
		<YcPicturePreview ref="preview" />
	</view>
</template>

<script setup lang="ts">
	import { ref, computed } from 'vue';
	import YcPicturePreview from "@/components/YcPicturePreview/YcPicturePreview.vue";
	let preview = ref<InstanceType<typeof YcPicturePreview>>();
	const photos = ref([
		{
			id: 1,
			url: 'https://img2.baidu.com/it/u=1028011339,1319212411&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=313',
			selected: false,
		},
		{
			id: 2,
			url: 'https://img0.baidu.com/it/u=1668365367,2821596851&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=684',
			selected: true,
		},
		{
			id: 3,
			url: 'https://img0.baidu.com/it/u=1668365367,2821596851&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=684',
			selected: false,
		},
		{
			id: 4,
			url: 'https://img0.baidu.com/it/u=1668365367,2821596851&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=684',
			selected: false,
		},
		{
			id: 5,
			url: 'https://img0.baidu.com/it/u=1668365367,2821596851&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=684',
			selected: false,
		},
		{
			id: 6,
			url: 'https://img0.baidu.com/it/u=1668365367,2821596851&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=684',
			selected: false,
		},

		{
			id: 7,
			url: 'https://img0.baidu.com/it/u=1668365367,2821596851&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=684',
			selected: false,
		},
		{
			id: 8,
			url: 'https://img0.baidu.com/it/u=1668365367,2821596851&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=684',
			selected: false,
		},
		{
			id: 9,
			url: 'https://img0.baidu.com/it/u=1668365367,2821596851&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=684',
			selected: false,
		},
		{
			id: 10,
			url: 'https://img0.baidu.com/it/u=1668365367,2821596851&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=684',
			selected: false,
		},

		{
			id: 11,
			url: 'https://img0.baidu.com/it/u=1668365367,2821596851&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=684',
			selected: false,
		},
	])
	const photoUrls = computed(() => {
		return photos.value.map(item => item.url)
	})
	const showBig = (currentIndex : number, list : Array<string>) => {
		preview.value?.previewImage(list, currentIndex);
	}
</script>

<style lang="scss" scoped>
 // ...
</style>
相关推荐
也无晴也无风雨1 小时前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络
Martin -Tang2 小时前
Vue 3 中,ref 和 reactive的区别
前端·javascript·vue.js
FakeOccupational3 小时前
nodejs 020: React语法规则 props和state
前端·javascript·react.js
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
曹天骄4 小时前
next中服务端组件共享接口数据
前端·javascript·react.js
阮少年、5 小时前
java后台生成模拟聊天截图并返回给前端
java·开发语言·前端
@Carey5 小时前
uniapp配置消息推送unipush 厂商推送设置配置 FCM 教程
uni-app
转角羊儿5 小时前
uni-app上拉加载更多⑩
uni-app
郝晨妤6 小时前
鸿蒙ArkTS和TS有什么区别?
前端·javascript·typescript·鸿蒙
AvatarGiser6 小时前
《ElementPlus 与 ElementUI 差异集合》Icon 图标 More 差异说明
前端·vue.js·elementui