手把手带你封装图片预览组件

一、前言

图片预览组件是一种常见的前端工具,它可以帮助我们在网页中实现图片的预览功能,让用户能够方便地浏览、切换和放大缩小图片。该组件通常可以支持多种图片格式,并提供用户友好的交互方式,例如点击、滑动、放大缩小等。通过使用图片预览组件,我们可以提升用户体验,使网页更加丰富和互动。
在这里插入图片描述

二、前置准备

(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
  }
}

四、测试结果

如下图所示,可以看到测试结果符合我们的预期。
在这里插入图片描述

欢迎关注公众号—代码分享站
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值