How to Create a Vue3 Custom Directive for Image Preview in an Admin Dashboard
This article walks through building a Vue3 custom directive that leverages Element‑Plus's ElImageViewer to provide a reusable image‑preview feature for a backend management system, covering directive basics, parameter details, step‑by‑step implementation, and integration into the main application.
作者:前端Ah 原文:https://juejin.cn/post/7324653675456364596
在 Vue3 项目中使用 Element‑Plus 的 ElImageViewer 实现自定义图片预览指令,避免直接使用 el-image 组件的内置预览。
Review Vue3 Directive Syntax
官方文档地址:https://cn.vuejs.org/guide/reusability/custom-directives.html
Simple Example
<div v-color="red">我是红色的文字</div> app.directive('color', (el, binding) => {
// called on mounted and updated
el.style.color = binding.value
})指令的关键参数: el :绑定的 DOM 元素。 binding :对象,包含 value 、 oldValue 、 arg 、 modifiers 、 instance 、 vnode 、 prevNode 等属性。
Step‑by‑Step Implementation
1. Create previewImageDirective.ts
import { DirectiveBinding, h, render } from 'vue'
import { ElImageViewer } from 'element-plus'
export default function (app) {
app.directive('previewImage', {
mounted(el: HTMLElement, binding: DirectiveBinding) {
// logic added later
}
})
}2. Directive Logic
Bind a click listener to the image element and set cursor: pointer on hover.
app.directive('previewImage', {
mounted(el: HTMLElement, binding: DirectiveBinding) {
el.addEventListener('click', () => {
el.style.cursor = 'pointer'
})
}
})Create a VNode for ElImageViewer using h, passing the image URL via urlList and enabling hideOnClickModal to allow closing by clicking the overlay.
vnode = h(ElImageViewer, {
urlList: [binding.value],
hideOnClickModal: true,
onClose: () => {
// cleanup will be added later
}
})Render the VNode into a dynamically created div and append it to document.body.
const previewBox = document.createElement('div')
previewBox.classList.add('preview-box')
render(vnode, previewBox)
document.body.appendChild(previewBox)In the onClose handler, remove the click listener and delete the created div from the DOM.
onClose: () => {
el.removeEventListener('click', /* same handler */)
document.body.removeChild(previewBox)
}完整指令代码示例:
export default function (app) {
app.directive('previewImage', {
mounted(el: HTMLElement, binding: DirectiveBinding) {
// 1. cursor style
el.style.cursor = 'pointer'
// 2. click to open preview
el.addEventListener('click', () => {
const previewBox = document.createElement('div')
previewBox.classList.add('preview-box')
const vnode = h(ElImageViewer, {
urlList: [binding.value],
hideOnClickModal: true,
onClose: () => {
document.body.removeChild(previewBox)
}
})
render(vnode, previewBox)
document.body.appendChild(previewBox)
})
}
})
}全局变量(如 previewBox 、 vnode )放在指令外部,以防在同一页面多次使用指令时产生多个实例导致资源浪费。
3. Import the Directive in main.ts
import imageDirective from './previewImageDirective'
const app = createApp(App)
imageDirective(app)完成上述步骤后,使用 v-previewImage="imageUrl" 的 img 元素即可在点击时弹出 Element‑Plus 的图片预览弹窗,并在点击遮罩层后自动关闭。
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
IoT Full-Stack Technology
Dedicated to sharing IoT cloud services, embedded systems, and mobile client technology, with no spam ads.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
