当前位置: 首页 > Web前端 > vue.js

封装Vue的浮动弹出图片查看器组件

时间:2023-03-31 20:11:51 vue.js

.image-viewer{position:fixed;z-index:99;top:0;left:0;height:100%;width:100%;background:rgba(0,0,0,0.6);cursor:move;transition:background0.3s;/*进出动画效果*/&.v-enter,&.v-leave-to{背景:rgba(0,0,0,0);}.image{位置:绝对;用户选择:无;变换原点:中心;will-change:transform,top,left;}}前言早年开发内部技术论坛时,为了实现一个图片浏览体验的过程,基于Vue开发了一个图片查看器组件,并实现思路简单整理了一下,希望能给大家提供一些帮助。先来看看效果图:从交互的角度来看,内容很简单。点击页面上的图片,图片的浮层会从图片当前位置弹出,从而达到图片浏览的目的。原理分析根据点击事件,获取被点击的图片元素,使当前图片元素不可见(通过visibility或opacity)创建阴影层在图片元素当前位置创建一个相同大小的图片元素创建动画来把图片放大到合适的大小(更新位置,比例)思路很清晰,实现起来也不难。实现方案因为最终目的是在Vue项目中使用,所以下面的方案直接封装成Vue组件。图像查看器基本结构图像查看器组件的视图结构很简单:复制代码简单分析一下:transition:外层嵌套transition组件,可以很方便我们以后做图片位移缩放的动画效果。image-viewer:root元素用于放置图片元素,同时也起到覆盖层的作用。image:点击图片后显示的悬浮图片即为该元素,后续操作均在该图片上进行。show(el):点击图片后会调用该方法,将图片元素传入组件,以非常简洁的风格展示图片查看器。绘制半透明阴影动画非常简单:.image-viewer{position:fixed;z-index:99;top:0;left:0;height:100%;width:100%;background:rgba(0,0,0,0.6);cursor:move;transition:background0.3s;/*进出动画效果*/&.v-enter,&.v-leave-to{背景:rgba(0,0,0,0);}.image{位置:绝对;用户选择:无;变换原点:中心;will-change:transform,top,left;}}复制代码从原来的地方弹出图片并放大。viewer中的元素(.image)弹出源图片元素(el)根据Vue数据驱动的思想,其实质就是应用startdata和enddata,实现图片弹出的动画效果原来的地方,并放置到合适的大小。这里,通过维护一个维度数据维度,根据该维度数据计算出目标图像元素的风格。exportdefault{data(){return{//...//图像维度信息dimension:null,};},computed:{//...//目标图像样式style(){if(!this.dimension)返回空值;const{scale,size:{width,height},位置:{top,left},translate:{x,y},}=this.dimension;返回{宽度:`${width}px`,高度:`${height}px`,顶部:`${top}px`,左侧:`${left}px`,转换:`translate3d(${x}px,${y}px,0)scale(${scale})`,transition:'transform0.3s',};},},methods:{show(el){el.style.opacity=0;这个.el=el;this.visible=true;this.dimension=getDimension(el);//从源图像中获取维度数据},},};copycode这里的dimension包含图片元素的如下信息:datadescriptionsize:{width,height}图片的实际宽高position:{top,left}图片scale的绝对位置实际比例图片元素的大小为图片的自然尺寸,用于后续图片缩放动画translate:{x,y}图片的位移位置,默认为0,用于后续图片缩放和位移动画的获取方法图像元素的维度:constgetDimension=(el)=>{const{naturalWidth,naturalHeight}=el;constrect=el.getBoundingClientRect();//放大后图片的宽高constheight=clamp(naturalHeight,0,window.innerHeight*0.9);constwidth=naturalWidth*(height/naturalHeight);返回{size:{width,height},position:{left:rect.left+(rect.width-width)/2,top:rect.top+(rect.height-height)/2,},scale:rect.height/height,翻译:{x:0,y:0},};};现在复制代码,我们已经在源图的最后叠加了一张同样大小的图片,然后根据屏幕大小将图片放大到合适的大小我们只需要修改show部分的逻辑,下一时刻更新dimension的值即可:exportdefault{//...methods:{show(el){el.style.opacity=0;这个.el=el;这。维度=getDimension(el);this.visible=true;doubleRaf(()=>{const{innerWidth,innerHeight}=window;const{size,position}=this.dimension;this.dimension={...this.dimension,//修改比例为1,即放大后的比例。scale:1,//计算位移以保持图像居中translate:{x:(innerWidth-size.width)/2-position.left,y:(innerHeight-size.height)/2-position.top,},};});},},};复制代码这里使用了DoubleRaf(DoubleRequestAnimationFrame),等待浏览器重新渲染后再执行:constdoubleRaf=(cb)=>{requestAnimationFrame(()=>{requestAnimationFrame(cb);});};复制代码这样图片放大的动画效果就出来了。同样,当我们点击阴影层触发图片浏览器关闭时,图片应该缩小并回到原来的位置:复制代码现在,图像视图组件部分的逻辑基本完成了。封装为函数调用为了让这个组件更加方便易用,我们将其封装为一个函数调用:importVuefrom'vue';从'./ImageViewer.vue'导入ImageViewer;constImageViewerConstructor=Vue.extend(ImageViewer);functionshowImage(el){//创建组件实例并调用组件的show方法letinstance=newImageViewerConstructor({el:document.createElement('div'),mounted(){this.show(el);},});//将组件根元素插入bodydocument.body.appendChild(instance.$el);//销毁函数:移除根元素,销毁组件函数destroy(){if(instance&&instance.$el){document.body.removeChild(instance.$el);instance.$destroy();instance=null;}}//当组件动画结束时,执行销毁函数instance.$once('hidden',destroy);//如果在父元素上调用该方法。当父元素被销毁时(比如切换路由),销毁函数也会执行if(this&&'$on'inthis){this.$on('hook:destroyed',destroy);}}showImage.install=(VueClass)=>{VueClass.prototype.$showImage=showImage;};exportdefaultshowImage;把代码复制到这里,组件的封装也完成了,可以愉快的在任何地方使用//===========main.js==========importVuefrom'视图';从'@bigo/vue-image-viewer'导入VueImageViewer;Vue.use(VueImageViewer);//==========App.vue===========<模板>

复制代码总结虽然功能比较简单,但是已经实现了主要的图片浏览功能。与大多数图片浏览插件相比,在用户体验方面要流畅很多,让用户拥有更流畅的视觉过渡,提供更好的沉浸式浏览体验。还有很多想法没有实现,比如浏览时拖拽图片,鼠标滚轮缩放,手势操作等。优化,移动体验优化,多图浏览等等,留给大家去思考。欢迎大家留言讨论,祝大家工作顺利,生活愉快!如果您觉得这篇文章对您有用,请给我们的开源项目点个star:http://github.crmeb.net/u/defu非常感谢!