如何禁止图片点击(不点击图片,直接实现el-image的大图预览功能)
导读: 接到个需求希望不需要点击图片可以直接进行放大、旋转等操作,...
接到个需求希望不需要点击图片可以直接进行放大 、旋转等操作 ,
el-image 有个组件是image-viewer 基于改组件进行了部分修改
image-viewer组件滚动放大是基于document绑定的事件 ,这样会导致右侧内容过长出现滚动条的时候 ,用鼠标滚轮滚动右侧内容 ,左侧图片会跟着相应的放大缩小 ,导致用户体验不佳 ,做了如下修改:
将鼠标滚动事件基于document改为基于el-image-viewer__wrapper
image-viewer .el-image-viewer__wrapper样式设置了position:fixed固定定位 ,导致拖动图片的时候容器区域会占据右侧的区域 ,做了如下修改:
将 .el-image-viewer__wrapper的固定定位改为绝对定位 ,把.el-image-viewer__img基于.el-image-viewer__canvas这个盒子进行绝对定位
完整代码如下:
<template> <transition name="viewer-fade"> <div tabindex="-1" ref="el-image-viewer__wrapper" class="el-image-viewer__wrapper" :style="{ z-index: viewerZIndex }"> <div class="el-image-viewer__mask" @click.self="handleMaskClick"></div> <!-- CLOSE --> <span class="el-image-viewer__btn el-image-viewer__close" @click="hide"> <i class="el-icon-close"></i> </span> <!-- ARROW --> <template v-if="!isSingle"> <span class="el-image-viewer__btn el-image-viewer__prev" :class="{ is-disabled: !infinite && isFirst }" @click="prev"> <i class="el-icon-arrow-left"/> </span> <span class="el-image-viewer__btn el-image-viewer__next" :class="{ is-disabled: !infinite && isLast }" @click="next"> <i class="el-icon-arrow-right"/> </span> </template> <!-- ACTIONS --> <div class="el-image-viewer__btn el-image-viewer__actions"> <div class="el-image-viewer__actions__inner"> <i class="el-icon-zoom-out" @click="handleActions(zoomOut)"></i> <i class="el-icon-zoom-in" @click="handleActions(zoomIn)"></i> <i class="el-image-viewer__actions__divider"></i> <i :class="mode.icon" @click="toggleMode"></i> <i class="el-image-viewer__actions__divider"></i> <i class="el-icon-refresh-left" @click="handleActions(anticlocelise)"></i> <i class="el-icon-refresh-right" @click="handleActions(clocelise)"></i> </div> </div> <!-- CANVAS --> <div class="el-image-viewer__canvas"> <img v-for="(url, i) in urlList" v-if="i === index" ref="img" class="el-image-viewer__img" :key="url" :src="currentImg" :style="imgStyle" @load="handleImgLoad" @error="handleImgError" @mousedown="handleMouseDown"> </div> </div> </transition> </template> <script> import { on, off } from element-ui/src/utils/dom; import { rafThrottle, isFirefox } from element-ui/src/utils/util; import { PopupManager } from element-ui/src/utils/popup; const Mode = { CONTAIN: { name: contain, icon: el-icon-full-screen }, ORIGINAL: { name: original, icon: el-icon-c-scale-to-original } }; const mousewheelEventName = isFirefox() ? DOMMouseScroll : mousewheel; export default { name: elImageViewer, props: { urlList: { type: Array, default: () => [] }, zIndex: { type: Number, default: 2000 }, onSwitch: { type: Function, default: () => {} }, onClose: { type: Function, default: () => {} }, initialIndex: { type: Number, default: 0 }, appendToBody: { type: Boolean, default: true }, maskClosable: { type: Boolean, default: true } }, data() { return { index: this.initialIndex, isShow: false, infinite: true, loading: false, mode: Mode.CONTAIN, transform: { scale: 1, deg: 0, offsetX: 0, offsetY: 0, enableTransition: false } }; }, computed: { isSingle() { return this.urlList.length <= 1; }, isFirst() { return this.index === 0; }, isLast() { return this.index === this.urlList.length - 1; }, currentImg() { return this.urlList[this.index]; }, imgStyle() { const { scale, deg, offsetX, offsetY, enableTransition } = this.transform; const style = { transform: `scale(${scale}) rotate(${deg}deg)`, transition: enableTransition ? transform .3s : , margin-left: `${offsetX}px`, margin-top: `${offsetY}px` }; if (this.mode === Mode.CONTAIN) { style.maxWidth = style.maxHeight = 100%; } return style; }, viewerZIndex() { const nextZIndex = PopupManager.nextZIndex(); return this.zIndex > nextZIndex ? this.zIndex : nextZIndex; } }, watch: { index: { handler: function(val) { this.reset(); this.onSwitch(val); } }, currentImg(val) { this.$nextTick(_ => { const $img = this.$refs.img[0]; if (!$img.complete) { this.loading = true; } }); } }, methods: { hide() { this.deviceSupportUninstall(); this.onClose(); }, deviceSupportInstall() { this._keyDownHandler = e => { e.stopPropagation(); const keyCode = e.keyCode; switch (keyCode) { // ESC case 27: this.hide(); break; // SPACE case 32: this.toggleMode(); break; // LEFT_ARROW case 37: this.prev(); break; // UP_ARROW case 38: this.handleActions(zoomIn); break; // RIGHT_ARROW case 39: this.next(); break; // DOWN_ARROW case 40: this.handleActions(zoomOut); break; } }; this._mouseWheelHandler = rafThrottle(e => { const delta = e.wheelDelta ? e.wheelDelta : -e.detail; if (delta > 0) { this.handleActions(zoomIn, { zoomRate: 0.015, enableTransition: false }); } else { this.handleActions(zoomOut, { zoomRate: 0.015, enableTransition: false }); } }); on(document, keydown, this._keyDownHandler); // on(document, mousewheelEventName, this._mouseWheelHandler); // 将鼠标滚动事件基于document改为基于el-image-viewer__wrapper if (this.$refs[el-image-viewer__wrapper]) { on(this.$refs[el-image-viewer__wrapper], mousewheelEventName, this._mouseWheelHandler); } }, deviceSupportUninstall() { off(document, keydown, this._keyDownHandler); off(document, mousewheelEventName, this._mouseWheelHandler); this._keyDownHandler = null; this._mouseWheelHandler = null; }, handleImgLoad(e) { this.loading = false; }, handleImgError(e) { this.loading = false; e.target.alt = 加载失败; }, handleMouseDown(e) { if (this.loading || e.button !== 0) return; const { offsetX, offsetY } = this.transform; const startX = e.pageX; const startY = e.pageY; this._dragHandler = rafThrottle(ev => { this.transform.offsetX = offsetX + ev.pageX - startX; this.transform.offsetY = offsetY + ev.pageY - startY; }); on(document, mousemove, this._dragHandler); on(document, mouseup, ev => { off(document, mousemove, this._dragHandler); }); e.preventDefault(); }, handleMaskClick() { if (this.maskClosable) { this.hide(); } }, reset() { this.transform = { scale: 1, deg: 0, offsetX: 0, offsetY: 0, enableTransition: false }; }, toggleMode() { if (this.loading) return; const modeNames = Object.keys(Mode); const modeValues = Object.values(Mode); const index = modeValues.indexOf(this.mode); const nextIndex = (index + 1) % modeNames.length; this.mode = Mode[modeNames[nextIndex]]; this.reset(); }, prev() { if (this.isFirst && !this.infinite) return; const len = this.urlList.length; this.index = (this.index - 1 + len) % len; }, next() { if (this.isLast && !this.infinite) return; const len = this.urlList.length; this.index = (this.index + 1) % len; }, handleActions(action, options = {}) { if (this.loading) return; const { zoomRate, rotateDeg, enableTransition } = { zoomRate: 0.2, rotateDeg: 90, enableTransition: true, ...options }; const { transform } = this; switch (action) { case zoomOut: if (transform.scale > 0.2) { transform.scale = parseFloat((transform.scale - zoomRate).toFixed(3)); } break; case zoomIn: transform.scale = parseFloat((transform.scale + zoomRate).toFixed(3)); break; case clocelise: transform.deg += rotateDeg; break; case anticlocelise: transform.deg -= rotateDeg; break; } transform.enableTransition = enableTransition; } }, mounted() { this.deviceSupportInstall(); if (this.appendToBody) { document.body.appendChild(this.$el); } // add tabindex then wrapper can be focusable via Javascript // focus wrapper so arrow key cant cause inner scroll behavior underneath this.$refs[el-image-viewer__wrapper].focus(); }, destroyed() { // if appendToBody is true, remove DOM node after destroy if (this.appendToBody && this.$el && this.$el.parentNode) { this.$el.parentNode.removeChild(this.$el); } } }; </script> <style scoped> .el-image-viewer__wrapper{ position: absolute; } .el-image-viewer__mask{ background: inherit; } .el-image-viewer__close{ display: none; } .el-image-viewer__actions{ height: 30px; width: 200px; } .el-image-viewer__actions__inner{ font-size: 18px; } .el-image-viewer__canvas{ overflow: hidden; position: relative; } .el-image-viewer__img{ position: absolute; } </style>vue文件中进行引用:
appendToBody:true表示将该组件放置于body层(body就是他的父) ,false表示放置在正常盒子里(imgCont-div是他的父)
<div class="imgCont" ref="imgCont"> <ElImageViewer :appendToBody="false" ref="elImageViewer" :url-list="[imgUrl]" ></ElImageViewer> </div>appendToBody:true 代码效果图:
appendToBody:false 代码效果图:
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!