vue3中使用medium-zoom方法實例代碼
簡介
Medium Zoom 是一個輕量級 JavaScript 庫,用于實現(xiàn)類似 Medium 網站的圖片點擊放大縮放效果。本文檔專注于在 Vue3 項目中的集成和使用。
核心特性
- ?? 響應式設計 - 完美適配移動端和桌面端
- ?? 高性能 - 優(yōu)化至 60fps 流暢動畫
- ?? 高清圖支持 - 通過
data-zoom-src屬性加載高清大圖 - ?? 可定制化 - 支持自定義邊距、背景、滾動偏移等
- ?? 事件系統(tǒng) - 完整的生命周期事件監(jiān)聽
- ?? 零依賴 - 無任何運行時依賴
- ?? 框架友好 - 完美支持 Vue3 組合式 API
安裝
使用 npm
npm install medium-zoom
使用 yarn
yarn add medium-zoom
使用 pnpm
pnpm add medium-zoom
Vue3 快速開始
方法一:封裝組件(推薦)
創(chuàng)建一個可復用的 ImageZoom.vue 組件:
<script setup lang="ts">
import { watch, type ImgHTMLAttributes, type ComponentPublicInstance } from 'vue'
import mediumZoom, { type Zoom, type ZoomOptions } from 'medium-zoom'
interface Props extends ImgHTMLAttributes {
options?: ZoomOptions
}
const props = defineProps<Props>()
let zoom: Zoom | null = null
function getZoom() {
if (zoom === null) {
zoom = mediumZoom(props.options)
}
return zoom
}
function attachZoom(ref: Element | ComponentPublicInstance | null) {
const image = ref as HTMLImageElement | null
const zoom = getZoom()
if (image) {
zoom.attach(image)
} else {
zoom.detach()
}
}
watch(() => props.options, (options) => {
const zoom = getZoom()
zoom.update(options || {})
})
</script>
<template>
<img :ref="attachZoom" v-bind="$attrs" />
</template>
使用封裝的組件
<script setup lang="ts">
import ImageZoom from './components/ImageZoom.vue'
</script>
<template>
<article>
<h1>我的圖片畫廊</h1>
<!-- 基礎使用 -->
<ImageZoom src="/images/photo-1.jpg" alt="照片1" />
<!-- 自定義背景色 -->
<ImageZoom
src="/images/photo-2.jpg"
alt="照片2"
:options="{ background: '#000000' }"
/>
<!-- 自定義邊距 -->
<ImageZoom
src="/images/photo-3.jpg"
alt="照片3"
:options="{ margin: 48, background: 'rgba(0,0,0,0.9)' }"
/>
<!-- 高清圖支持 -->
<ImageZoom
src="/images/thumbnail.jpg"
data-zoom-src="/images/hd-image.jpg"
alt="高清圖片"
/>
</article>
</template>
方法二:在 Composable 中使用
創(chuàng)建 useImageZoom.ts:
import { onMounted, onUnmounted, ref, type Ref } from 'vue'
import mediumZoom, { type Zoom, type ZoomOptions } from 'medium-zoom'
export function useImageZoom(
selector?: string | HTMLElement,
options?: ZoomOptions
) {
const zoom: Ref<Zoom | null> = ref(null)
onMounted(() => {
zoom.value = mediumZoom(selector, options)
})
onUnmounted(() => {
zoom.value?.detach()
})
return {
zoom,
open: () => zoom.value?.open(),
close: () => zoom.value?.close(),
toggle: () => zoom.value?.toggle(),
}
}
使用 Composable:
<script setup lang="ts">
import { onMounted } from 'vue'
import { useImageZoom } from './composables/useImageZoom'
// 初始化 zoom
const { zoom, open, close } = useImageZoom('[data-zoomable]', {
margin: 24,
background: '#BADA55',
})
// 也可以在掛載后動態(tài)附加圖片
onMounted(() => {
zoom.value?.attach('.gallery-image')
})
</script>
<template>
<div>
<img src="/image-1.jpg" data-zoomable alt="圖片1" />
<img src="/image-2.jpg" data-zoomable alt="圖片2" />
<img src="/image-3.jpg" class="gallery-image" alt="圖片3" />
<!-- 手動控制按鈕 -->
<button @click="open">放大第一張圖片</button>
<button @click="close">關閉縮放</button>
</div>
</template>
方法三:直接在組件中使用
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
import mediumZoom from 'medium-zoom'
const zoomRef = ref(null)
onMounted(() => {
zoomRef.value = mediumZoom('.zoomable', {
margin: 24,
background: '#fff',
scrollOffset: 40,
})
})
onUnmounted(() => {
zoomRef.value?.detach()
})
</script>
<template>
<div>
<img src="/image.jpg" class="zoomable" alt="可縮放圖片" />
</div>
</template>
配置選項 (ZoomOptions)
| 屬性 | 類型 | 默認值 | 說明 |
|---|---|---|---|
margin | number | 0 | 縮放圖片外的空白邊距(像素) |
background | string | "#fff" | 遮罩層背景色,支持任何 CSS 顏色值 |
scrollOffset | number | 40 | 滾動多少像素后自動關閉縮放 |
container | string | HTMLElement | object | null | 指定縮放渲染的容器視口 |
template | string | HTMLTemplateElement | null | 自定義模板元素 |
配置示例
const options: ZoomOptions = {
margin: 48, // 48px 邊距
background: 'rgba(0,0,0,0.9)', // 半透明黑色背景
scrollOffset: 100, // 滾動 100px 后關閉
container: '#zoom-container', // 在指定容器內縮放
}
API 方法
open(options?: { target?: HTMLElement }): Promise<Zoom>
打開縮放,返回 Promise。
zoom.value?.open()
// 或指定目標圖片
zoom.value?.open({ target: imgElement })
close(): Promise<Zoom>
關閉縮放,返回 Promise。
zoom.value?.close()
toggle(options?: { target?: HTMLElement }): Promise<Zoom>
切換縮放狀態(tài)(打開/關閉)。
zoom.value?.toggle()
attach(...selectors): Zoom
附加圖片到縮放實例。
zoom.value?.attach('#image-1', '#image-2')
zoom.value?.attach(document.querySelector('#image-3'))
detach(...selectors): Zoom
從縮放實例中移除圖片。
zoom.value?.detach('#image-1')
zoom.value?.detach() // 移除所有圖片
update(options: ZoomOptions): Zoom
更新配置選項。
zoom.value?.update({
background: '#000',
margin: 50
})
clone(options?: ZoomOptions): Zoom
克隆一個新的縮放實例,合并新配置。
const newZoom = zoom.value?.clone({ margin: 100 })
on(type: string, listener: Function, options?): Zoom
注冊事件監(jiān)聽器。
zoom.value?.on('open', (event) => {
console.log('圖片已打開', event.detail.zoom)
})
off(type: string, listener: Function, options?): Zoom
移除事件監(jiān)聽器。
const handler = (event) => { /* ... */ }
zoom.value?.on('open', handler)
zoom.value?.off('open', handler)
getOptions(): ZoomOptions
獲取當前配置選項。
const currentOptions = zoom.value?.getOptions()
getImages(): HTMLElement[]
獲取所有已附加的圖片元素。
const images = zoom.value?.getImages()
getZoomedImage(): HTMLElement | null
獲取當前正在縮放的圖片元素。
const currentImage = zoom.value?.getZoomedImage()
事件系統(tǒng)
可用事件
| 事件名 | 觸發(fā)時機 | 說明 |
|---|---|---|
open | 調用 open() 方法時立即觸發(fā) | 縮放動畫開始前 |
opened | 縮放動畫完成后 | 圖片已完全放大 |
close | 調用 close() 方法時立即觸發(fā) | 關閉動畫開始前 |
closed | 關閉動畫完成后 | 圖片已完全縮小 |
detach | 調用 detach() 方法時 | 圖片從實例中移除 |
update | 調用 update() 方法時 | 配置選項已更新 |
Vue3 中使用事件
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import mediumZoom from 'medium-zoom'
const zoom = ref(null)
const zoomCount = ref(0)
onMounted(() => {
zoom.value = mediumZoom('[data-zoomable]')
// 監(jiān)聽打開事件
zoom.value.on('open', (event) => {
console.log('開始縮放:', event.target.alt)
})
// 監(jiān)聽打開完成事件
zoom.value.on('opened', (event) => {
zoomCount.value++
console.log(`已縮放 ${zoomCount.value} 次`)
})
// 監(jiān)聽關閉事件
zoom.value.on('close', () => {
console.log('開始關閉縮放')
})
// 監(jiān)聽關閉完成事件
zoom.value.on('closed', () => {
console.log('縮放已關閉')
})
// 單次事件監(jiān)聽
zoom.value.on('open', (event) => {
console.log('這個只觸發(fā)一次')
}, { once: true })
})
</script>
<template>
<div>
<img src="/image.jpg" data-zoomable alt="圖片" />
<p>已縮放次數: {{ zoomCount }}</p>
</div>
</template>
高級用法
1. 高清圖加載
使用 data-zoom-src 屬性指定高清大圖:
<template>
<ImageZoom
src="/thumbnails/small.jpg"
data-zoom-src="/images/large-hd.jpg"
alt="高清圖片"
/>
</template>
2. 在 Markdown 渲染中使用
適用于博客、文檔等場景:
<script setup lang="ts">
import { onMounted, ref, nextTick } from 'vue'
import mediumZoom from 'medium-zoom'
import MarkdownIt from 'markdown-it'
const md = new MarkdownIt()
const content = ref('')
const zoom = ref(null)
const markdown = `
# 我的文章


`
onMounted(async () => {
content.value = md.render(markdown)
await nextTick()
// 為所有 markdown 渲染的圖片添加縮放
zoom.value = mediumZoom('.markdown-body img', {
background: 'rgba(255,255,255,0.95)',
margin: 24
})
})
</script>
<template>
<div class="markdown-body" v-html="content"></div>
</template>
3. 自定義容器
在指定容器內縮放:
<script setup lang="ts">
import { onMounted } from 'vue'
import mediumZoom from 'medium-zoom'
onMounted(() => {
mediumZoom('[data-zoomable]', {
container: '#custom-container',
background: 'transparent'
})
})
</script>
<template>
<div id="custom-container" style="position: relative; height: 500px;">
<img src="/image.jpg" data-zoomable alt="圖片" />
</div>
</template>
4. 動態(tài)添加/移除圖片
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import mediumZoom from 'medium-zoom'
const images = ref(['/img1.jpg', '/img2.jpg'])
const zoom = ref(null)
onMounted(() => {
zoom.value = mediumZoom('.gallery img')
})
function addImage() {
const newImg = `/img${images.value.length + 1}.jpg`
images.value.push(newImg)
// 下一幀后附加新圖片
nextTick(() => {
const newElement = document.querySelector(`.img-${images.value.length - 1}`)
zoom.value?.attach(newElement)
})
}
function removeImage(index: number) {
const imgElement = document.querySelector(`.img-${index}`)
zoom.value?.detach(imgElement)
images.value.splice(index, 1)
}
</script>
<template>
<div class="gallery">
<img
v-for="(src, index) in images"
:key="index"
:src="src"
:class="`img-${index}`"
alt="圖片"
/>
<button @click="addImage">添加圖片</button>
</div>
</template>
5. 從外部按鈕觸發(fā)縮放
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import mediumZoom from 'medium-zoom'
const zoom = ref(null)
const imageRef = ref(null)
onMounted(() => {
zoom.value = mediumZoom(imageRef.value)
})
function handleZoom() {
zoom.value?.toggle({ target: imageRef.value })
}
</script>
<template>
<div>
<img ref="imageRef" src="/image.jpg" alt="圖片" />
<button @click="handleZoom">點擊縮放圖片</button>
</div>
</template>
6. 圖片畫廊示例
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import mediumZoom from 'medium-zoom'
const zoom = ref(null)
const gallery = [
{ id: 1, src: '/gallery/img1.jpg', thumb: '/gallery/thumb1.jpg', alt: '風景1' },
{ id: 2, src: '/gallery/img2.jpg', thumb: '/gallery/thumb2.jpg', alt: '風景2' },
{ id: 3, src: '/gallery/img3.jpg', thumb: '/gallery/thumb3.jpg', alt: '風景3' },
]
onMounted(() => {
zoom.value = mediumZoom('.gallery-image', {
margin: 48,
background: '#000',
})
zoom.value.on('opened', (event) => {
console.log(`正在查看: ${event.target.alt}`)
})
})
</script>
<template>
<div class="gallery-grid">
<div v-for="item in gallery" :key="item.id" class="gallery-item">
<img
:src="item.thumb"
:data-zoom-src="item.src"
:alt="item.alt"
class="gallery-image"
/>
<p>{{ item.alt }}</p>
</div>
</div>
</template>
<style scoped>
.gallery-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
}
.gallery-image {
width: 100%;
cursor: zoom-in;
transition: opacity 0.3s;
}
.gallery-image:hover {
opacity: 0.8;
}
</style>
樣式定制
如果需要自定義 z-index(避免與其他 UI 框架沖突):
/* 在全局樣式中添加 */
.medium-zoom-overlay,
.medium-zoom-image--opened {
z-index: 9999;
}
自定義動畫時長:
.medium-zoom-image--opened {
transition: transform 300ms cubic-bezier(0.2, 0, 0.2, 1);
}
TypeScript 支持
完整的 TypeScript 類型定義:
import mediumZoom, {
type Zoom,
type ZoomOptions,
type ZoomSelector,
type ZoomOpenOptions
} from 'medium-zoom'
// Zoom 實例類型
const zoom: Zoom = mediumZoom()
// 配置選項類型
const options: ZoomOptions = {
margin: 24,
background: '#fff',
scrollOffset: 40,
}
// 選擇器類型
const selector: ZoomSelector = '.image' // string | HTMLElement | HTMLElement[] | NodeList
常見問題
Q: 縮放的圖片看不見?
A: 某些 UI 框架可能設置了較高的 z-index,需要手動設置:
.medium-zoom-overlay,
.medium-zoom-image--opened {
z-index: 9999;
}
Q: 在 v-for 中使用無效?
A: 確保在 DOM 更新后再附加圖片:
<script setup>
import { nextTick } from 'vue'
async function addImages() {
images.value.push(newImage)
await nextTick()
zoom.value?.attach('.new-image')
}
</script>
Q: 如何在路由切換時清理?
A: 使用 onUnmounted 鉤子:
<script setup>
import { onUnmounted } from 'vue'
onUnmounted(() => {
zoom.value?.detach()
})
</script>
瀏覽器支持
- Chrome 36+
- Firefox 34+
- Safari 9+
- Edge 12+
- IE 10+ (需要 template polyfill)
參考資源
提示: 本文檔基于 medium-zoom 庫分析生成,適用于 Vue 3.x 版本項目。
到此這篇關于vue3中使用medium-zoom方法的文章就介紹到這了,更多相關vue3使用medium-zoom內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
vue實現(xiàn)動態(tài)路由的方法及路由原理解析
這篇文章主要介紹了路由原理及vue實現(xiàn)動態(tài)路由,Vue Router 提供了豐富的 API,可以輕松地實現(xiàn)路由功能,并支持路由參數、查詢參數、命名路由、嵌套路由等功能,可以滿足不同應用程序的需求,需要的朋友可以參考下2023-06-06
使用 vue 實現(xiàn)滅霸打響指英雄消失的效果附demo
這篇文章主要介紹了使用 vue 實現(xiàn)滅霸打響指英雄消失的效果 demo,需要的朋友可以參考下2019-05-05
easycom模式開發(fā)UNI-APP組件調用必須掌握的實用技巧
uni-app基于VUE開發(fā),通常組件的使用都是先安裝,然后全局或者局部引入,注冊,今天通過本文給大家分享easycom模式開發(fā)UNI-APP組件調用必須掌握的實用技巧,需要的朋友一起看看吧2021-08-08

