一、前言
图片预览组件是一种常见的前端工具,它可以帮助我们在网页中实现图片的预览功能,让用户能够方便地浏览、切换和放大缩小图片。该组件通常可以支持多种图片格式,并提供用户友好的交互方式,例如点击、滑动、放大缩小等。通过使用图片预览组件,我们可以提升用户体验,使网页更加丰富和互动。
二、前置准备
(1)创建文件
(2)编写自动注册全局组件的插件代码,并在main.ts中调用setupComponent函数(因为我使用的构建工具是webpack)
import { App } from "vue";
const componentPlugin = {
install(app: App) {
// 获取组件文件列表
const comRequire = require.context('../components', true, /\.vue$/)
comRequire.keys().forEach(filePath => {
// 获取组件名
const temp = filePath.split('/')
const name = temp[temp.length - 1].split('.')[0]
// 获取组件配置
const config = comRequire(filePath).default
app.component(name, config)
})
}
}
export function setupComponent(app: App) {
app.use(componentPlugin)
}
三、开始封装
图片预览组件主要功能包括了放大、缩小、旋转等功能。该组件接收一个图片对象。页面使用方式如下:
<template>
<ImagePreview :imgData="imgData"></ImagePreview>
</template>
<script setup lang="ts">
import { useHome } from '@/store/home'
const {
imgData,
} = useHome()
</script>
// 页面的hooks,主要提供图片对象的操作
import HeadImg from '@images/head.jpg'
export interface IImgData {
name:string
src:string
scale:number
rotate:number
}
export function useHome(){
const imgData :IImgData= {
name:'头像',
src:HeadImg,
scale:1,
rotate:0
}
return {
imgData,
}
}
我们在ImagePreview.vue文件绘制页面,当点击图片时,将蒙层包含里边的图片展示出来(通过isShowPreView进行判断是否预览)。我们给蒙层添加点击事件,将isShowPreView设置为false。为了防止点击蒙层里的图片也会触发到给蒙层添加的点击事件,需要使用操作符.self。
<template>
<img :src="imgData.src" alt="" class=" cursor-pointer" @click="setShowPreview(true)">
<Transition name="fade">
<div v-show="isShowPreView" class="w-full h-full bg-[rgba(0,0,0,.5)] fixed top-0 left-0" @click.self="cancelShow">
<img :src="img.src" alt="" class="w-96 h-96 absolute top-0 left-0 right-0 bottom-0 m-auto transform transition-all "
:style="{ transform: `scale(${img.scale}) rotate(${img.rotate}deg)` }">
<div class=" absolute bottom-12 left-1/2 transform -translate-x-1/2">
<ImageToolBar @change="changeImgData"></ImageToolBar>
</div>
</div>
</Transition>
</template>
<script setup lang="ts">
import { IImgData } from "@/store/home";
import { useImagePreview } from "./src/hooks/useImagePreview";
export interface IImagePreviewProps {
imgData: IImgData
}
const props = defineProps<IImagePreviewProps>()
const {
isShowPreView,
setShowPreview,
img,
cancelShow,
changeImgData
} = useImagePreview(props.imgData)
</script>
<style scoped>
.fade-enter-from,
.fade-leave-to{
opacity: 0;
}
.fade-enter-active{
transition: all .2s ease-in;
}
.fade-leave-active{
transition: all .2s ease-out;
}
</style>
接下来封装图片工具栏组件,其中包含了放大、缩小、逆时针旋转、顺时针旋转。我们需要准备一个数组,包含每一个功能的配置和回调事件函数,当点击某一个功能时,就通知父组件更新图片数据。
<template>
<div class="bg-white flex items-center py-2">
<img :src="barItem.src" :alt="barItem.alt" v-for="barItem in bar" :key="barItem.id"
class="w-12 h-12 mx-4 cursor-pointer hover:shadow-lg" @click="barItem.onClick">
</div>
</template>
<script setup lang="ts">
import { useImageToolBar } from '../hooks/useImageToolBar';
const { bar } = useImageToolBar()
</script>
import AmplifyIcon from '@images/amplify.svg'
import ReduceIcon from '@images/reduce.svg'
import RotateLeftIcon from '@images/rotate_left.svg'
import RotateRightIcon from '@images/rotate_right.svg'
import { getCurrentInstance } from 'vue'
export interface IBar{
id:number
src:string
alt:string
onClick:() => void
}
export function useImageToolBar() {
const {emit} = getCurrentInstance()
const bar:IBar[] = [
{
id: 1,
src: AmplifyIcon,
alt: '放大',
onClick: () => {
emit('change',{
event:'amplify',
data:0.2
})
}
}, {
id: 2,
src: ReduceIcon,
alt: '缩小',
onClick: () => {
emit('change',{
event:'reduce',
data:0.2
})
}
}, {
id: 3,
src: RotateLeftIcon,
alt: '逆时针旋转',
onClick: () => {
emit('change',{
event:'rotateLeft',
data:90
})
}
}, {
id: 4,
src: RotateRightIcon,
alt: '顺时针旋转',
onClick: () => {
emit('change',{
event:'rotateRight',
data:90
})
}
}
]
return {
bar
}
}
做到这发现了问题,就是点击蒙层隐藏,再打开预览,发现图片是上次的状态。我们需要重置图片的旋转和缩放的状态。但是当我们重置完后,发现在蒙层隐藏的同时,我们可以看到还原状态的过程,这个问题是因为我们给预览添加了动画(150ms),所以需要设置一个定时器,等过了150ms再执行重置状态的操作,问题就可以解决了。
import { IImgData } from "@/store/home"
import { getCurrentInstance, ref } from "vue"
export function useImagePreview(imgData: IImgData) {
/**将图片数据变成响应式数据 */
const img = ref(imgData)
/**是否预览 */
const isShowPreView = ref<boolean>(false)
/**重置状态的定时器 */
let timer: NodeJS.Timer | null = null
/**
* 设置预览状态
*/
const setShowPreview = (value: boolean) => {
isShowPreView.value = value
}
/**
* 设置预览
*/
const cancelShow = () => {
if (timer) {
clearTimeout(timer)
timer = null
}
isShowPreView.value = false
timer = setTimeout(() => {
img.value.rotate = 0
img.value.scale = 1
}, 150);
}
/**
* 改变图片属性
*/
const changeImgData = (value) => {
console.log(value);
switch (value.event) {
case 'amplify':
img.value.scale += value.data
break;
case 'reduce':
img.value.scale -= value.data
break;
case 'rotateLeft':
img.value.rotate += value.data
break;
case 'rotateRight':
img.value.rotate -= value.data
break;
}
img.value.scale = img.value.scale > 2.8 ? 2.8 : (img.value.scale < 0.2 ? 0.2 : img.value.scale)
}
return {
isShowPreView,
setShowPreview,
img,
cancelShow,
changeImgData
}
}
四、测试结果
如下图所示,可以看到测试结果符合我们的预期。
欢迎关注公众号—代码分享站