vue实现图片插件
Vue 图片插件实现方案
基础组件封装
创建可复用的图片组件,支持懒加载、错误处理和占位图
<template>
<div class="image-wrapper">
<img
:src="realSrc"
:alt="altText"
@load="handleLoad"
@error="handleError"
v-if="!isError"
>
<div v-else class="error-placeholder">
{{ errorText }}
</div>
</div>
</template>
<script>
export default {
props: {
src: String,
altText: { type: String, default: 'image' },
placeholder: { type: String, default: 'data:image/svg+xml...' },
errorText: { type: String, default: '加载失败' }
},
data() {
return {
isError: false,
isLoading: true
}
},
computed: {
realSrc() {
return this.isLoading ? this.placeholder : this.src
}
},
methods: {
handleLoad() {
this.isLoading = false
this.$emit('loaded')
},
handleError() {
this.isError = true
this.$emit('error')
}
}
}
</script>
懒加载实现
结合 IntersectionObserver API 实现视口检测

const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target
img.src = img.dataset.src
observer.unobserve(img)
}
})
})
export default {
mounted() {
observer.observe(this.$el.querySelector('img'))
},
beforeDestroy() {
observer.disconnect()
}
}
图片预览功能
通过指令实现点击放大预览
Vue.directive('preview', {
bind(el, binding) {
el.style.cursor = 'zoom-in'
el.addEventListener('click', () => {
const previewEl = document.createElement('div')
previewEl.className = 'image-preview-overlay'
previewEl.innerHTML = `
<img src="${binding.value}" class="preview-image">
<button class="close-btn">×</button>
`
document.body.appendChild(previewEl)
previewEl.querySelector('.close-btn').addEventListener('click', () => {
document.body.removeChild(previewEl)
})
})
}
})
性能优化方案
实现渐进式加载和WebP格式支持

export default {
computed: {
optimizedSrc() {
const supportsWebP = document.createElement('canvas')
.toDataURL('image/webp')
.indexOf('data:image/webp') === 0
const src = this.src.replace(/\.(jpg|png)$/, supportsWebP ? '.webp' : '$&')
return `${src}?width=${this.width}&quality=${this.quality}`
}
}
}
插件化封装
将功能封装为可安装的Vue插件
const ImagePlugin = {
install(Vue, options = {}) {
Vue.component(options.componentName || 'SmartImage', ImageComponent)
Vue.directive('preview', previewDirective)
Vue.prototype.$image = {
preload(urls) {
return Promise.all(urls.map(url => new Promise((resolve) => {
const img = new Image()
img.src = url
img.onload = resolve
})))
}
}
}
}
export default ImagePlugin
样式处理方案
添加必要的CSS样式增强用户体验
.image-wrapper {
position: relative;
overflow: hidden;
}
.image-preview-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
}
.preview-image {
max-width: 90vw;
max-height: 90vh;
object-fit: contain;
}






