diff --git a/src/components/ImageViewer/index.vue b/src/components/ImageViewer/index.vue new file mode 100644 index 0000000..1cc50bf --- /dev/null +++ b/src/components/ImageViewer/index.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/src/components/PreviewImage/index.vue b/src/components/PreviewImage/index.vue new file mode 100644 index 0000000..cbd0f92 --- /dev/null +++ b/src/components/PreviewImage/index.vue @@ -0,0 +1,149 @@ + + + + + diff --git a/src/directive/index.ts b/src/directive/index.ts index 6ae5177..58120a2 100644 --- a/src/directive/index.ts +++ b/src/directive/index.ts @@ -2,12 +2,14 @@ import type { App } from 'vue'; import { authDirective } from '/@/directive/authDirective'; import { wavesDirective, dragDirective } from '/@/directive/customDirective'; import { debounceDirective } from './debounceDirective'; +import { previewDirective } from './previewDirective'; /** * 导出指令方法:v-xxx * @methods authDirective 用户权限指令,用法:v-auth * @methods wavesDirective 按钮波浪指令,用法:v-waves * @methods dragDirective 自定义拖动指令,用法:v-drag + * @methods previewDirective 图片预览指令,用法:v-preview */ export function directive(app: App) { // 用户权限指令 @@ -19,4 +21,7 @@ export function directive(app: App) { //防抖指令 debounceDirective(app); + + // 图片预览指令 + app.directive('preview', previewDirective); } diff --git a/src/directive/previewDirective.ts b/src/directive/previewDirective.ts new file mode 100644 index 0000000..91ef1ce --- /dev/null +++ b/src/directive/previewDirective.ts @@ -0,0 +1,40 @@ +import type { Directive, DirectiveBinding } from 'vue'; +import { useImagePreview } from '../utils/imagePreview'; + +const { previewSingleImage } = useImagePreview(); + +export const previewDirective: Directive = { + mounted(el: HTMLElement, binding: DirectiveBinding) { + const imgEl = el.tagName === 'IMG' ? el : el.querySelector('img'); + if (!imgEl) return; + + const urlList = binding.value?.urlList || []; + const disabled = binding.value?.disabled || false; + + if (!disabled) { + imgEl.style.cursor = 'pointer'; + imgEl.addEventListener('click', (e) => { + e.stopPropagation(); + const src = (imgEl as HTMLImageElement).src; + if (urlList.length > 0) { + const { showImagePreview } = useImagePreview(); + const index = urlList.indexOf(src); + showImagePreview({ + urlList, + initialIndex: index >= 0 ? index : 0, + }); + } else { + previewSingleImage(src); + } + }); + } + }, + + unmounted(el: HTMLElement) { + const imgEl = el.tagName === 'IMG' ? el : el.querySelector('img'); + if (!imgEl) return; + imgEl.removeEventListener('click', () => {}); + }, +}; + +export default previewDirective; diff --git a/src/utils/imagePreview.ts b/src/utils/imagePreview.ts new file mode 100644 index 0000000..76cede9 --- /dev/null +++ b/src/utils/imagePreview.ts @@ -0,0 +1,71 @@ +import { createApp, markRaw, h, ref, type App } from 'vue'; +import ImageViewer from '../components/ImageViewer/index.vue'; + +interface ImagePreviewOptions { + urlList: string[]; + initialIndex?: number; +} + +let imageViewerInstance: any = null; + +export const useImagePreview = () => { + const showImagePreview = (options: ImagePreviewOptions) => { + const { urlList, initialIndex = 0 } = options; + + if (!urlList || urlList.length === 0) { + return; + } + + if (imageViewerInstance) { + imageViewerInstance.unmount(); + imageViewerInstance = null; + } + + const container = document.createElement('div'); + document.body.appendChild(container); + + const app = createApp({ + components: { ImageViewer }, + setup() { + const visible = ref(true); + + const handleClose = () => { + visible.value = false; + setTimeout(() => { + app.unmount(); + if (document.body.contains(container)) { + document.body.removeChild(container); + } + imageViewerInstance = null; + }, 300); + }; + + return () => + h(ImageViewer, { + modelValue: visible.value, + 'onUpdate:modelValue': (val: boolean) => { + visible.value = val; + if (!val) { + handleClose(); + } + }, + urlList, + initialIndex, + onClose: handleClose, + }); + }, + }); + + imageViewerInstance = app; + app.mount(container); + }; + + const previewSingleImage = (url: string) => { + showImagePreview({ urlList: [url] }); + }; + + return { + showImagePreview, + previewSingleImage, + }; +}; diff --git a/src/views/blog/albums/pictures.vue b/src/views/blog/albums/pictures.vue index 28a3b05..92db644 100644 --- a/src/views/blog/albums/pictures.vue +++ b/src/views/blog/albums/pictures.vue @@ -17,20 +17,16 @@
- +
-
- - 查看 -
删除 @@ -55,18 +51,17 @@ -
+ + +