#頭條創作挑戰賽#
今天給大家分享 vue3.js 開發圖檔切換預覽元件。
preview-image 圖檔預覽元件支援左右切換、旋轉、放大/縮小、重置等功能。
<Preview
v-model="showPreview"
:previewSrcList="previewSrcList"
:current="current"
:infinite="infinite"
:opacity="opacity"
:shadeClose="shadeClose"
:z-index="zIndex"
:zoom="zoom"
:toolbar="toolbar"
:tooltip="tooltip"
:anim="anim"
:appendToBody="appendToBody"
@close="closePreview"
@switch="switchPreview"
>
<!-- 預覽插槽 -->
<slot name="preview"></slot>
</Preview>
底部工具欄采用透明磨砂效果,支援tooltip提示。
參數配置
const props = defineProps({
// 是否顯示
modelValue: { type: Boolean, default: false },
// 開啟圖檔預覽功能
previewSrcList: { type: [String, Array] },
// 開啟預覽是否展示底部工具欄
toolbar: { type: [Boolean, String], default: true },
// 是否展示工具欄的提示
tooltip: { type: [Boolean, String] },
// 目前預覽圖檔索引
current: { type: [Number, String] },
// 是否可以無限循環預覽
infinite: { type: [Boolean, String], default: true },
// 遮罩層透明度
opacity: { type: [Number, String] },
// 點選遮罩層關閉預覽
shadeClose: { type: [Boolean, String], default: true },
// 縮放比例
zoom: { type: [Number, String], default: 1.1 },
// 設定圖檔預覽的z-index
zIndex: { type: [Number, String], default: 2023 },
// 預覽彈窗動畫(down / up)
anim: { type: String, default: 'down' },
// 預覽圖檔是否插入到body
appendToBody: { type: [Boolean, String] }
})
Image預覽模闆
<template>
<teleport to="body" :disabled="!appendToBody">
<transition name="ve-image-preview-fade" mode="out-in" appear>
<div
v-if="visible"
ref="previewImgRef"
class="ve-image-preview__wrapper"
:style="[
{'z-index': zIndex}
]"
>
<!-- 遮罩層 -->
<div class="ve-image-preview__mask" @click.self="handleMask" :style="{opacity}"></div>
<!-- 工具欄 -->
<div class="ve-image-preview__toolbar">
<Icon name="ve-icon-prev" v-tooltip="{content: '上一張'}" cursor @click="handlePrev" />
<Icon name="ve-icon-next" v-tooltip="{content: '下一張'}" cursor @click="handleNext" />
<Icon name="ve-icon-rotateLeft" v-tooltip="{content: '向左旋轉'}" cursor @click="handleAction('rotateLeft')" />
<Icon name="ve-icon-rotateRight" v-tooltip="{content: '向右旋轉'}" cursor @click="handleAction('rotateRight')" />
<Icon name="ve-icon-reset" v-tooltip="{content: '原始尺寸'}" cursor @click="handleAction('reset')" />
<Icon name="ve-icon-zoomBig" v-tooltip="{content: '放大'}" cursor @click="handleAction('zoomIn')" />
<Icon name="ve-icon-zoomSmall" v-tooltip="{content: '縮小'}" cursor @click="handleAction('zoomOut')" />
<Icon name="ve-icon-guanbi" v-tooltip="{content: '關閉'}" cursor @click="handleClose" />
</div>
<!-- 預覽圖 -->
<transition :name="`ve-image-preview-slide-${anim}`" mode="out-in" appear>
<div class="ve-image-preview__gallery" :class="{'ve-image-preview__loading': loading}">
<img
ref="imgRef"
class="ve-image-preview__img"
:src="activeImg"
:style="imgStyle"
@load="handleLoad"
@error="handleError"
@mousedown="handleMousedown"
@mousewheel="handleMouseWheel"
/>
</div>
</transition>
<!-- 優化拖拽卡頓 -->
<div ref="dragfixRef" class="ve-image-preview__dragfix"></div>
</div>
</transition>
</teleport>
</template>
/* 工具欄事件 */
const handleAction = (action) => {
if(loading.value) return
switch(action) {
case 'rotateLeft':
handleRotateLeft()
break
case 'rotateRight':
handleRotateRight()
break
case 'reset':
handleReset()
break
case 'zoomIn':
handleZoomIn()
break
case 'zoomOut':
handleZoomOut()
break
}
transform.value.enableTransition = true
}
// 上一張
const handlePrev = () => {
if(isFirst.value && !props.infinite) return
setActive(activeIndex.value - 1)
}
// 下一張
const handleNext = () => {
if(isLast.value && !props.infinite) return
setActive(activeIndex.value + 1)
}
// 向左旋轉
const handleRotateLeft = () => {
transform.value.deg -= 90
}
// 向右旋轉
const handleRotateRight = () => {
transform.value.deg += 90
}
// 縮放到原始尺寸
const handleReset = () => {
transform.value = {
scale: 1,
deg: 0,
offsetX: 0,
offsetY: 0
}
}
// 放大
const handleZoomIn = () => {
if(transform.value.scale < 7) {
transform.value.scale = Number.parseFloat((transform.value.scale * props.zoom).toFixed(3))
}
}
// 縮小
const handleZoomOut = () => {
if(transform.value.scale > .2) {
transform.value.scale = Number.parseFloat((transform.value.scale / props.zoom).toFixed(3))
}
}
// 關閉預覽
const handleClose = () => {
handleReset()
emit('update:modelValue', false)
emit('close')
}
ok,基于vue3開發圖檔預覽元件就分享到這裡。