关于vue.js弹窗组件的知识点总结
首先在开发时需要考虑以下三点:
1、进入和弹出的动画效果。
2、z-index的控制
3、overlay遮盖层
关于动画
vue对于动画的处理相对简单,给组件加入csstransition动画即可
<template> <divclass="modal"transition="modal-scale"> <!--省略其它内容--> </div> </template> <script> //... </script> <style> .modal-scale-transition{ transition:transform,opacity.3sease; } .modal-scale-enter, .modal-scale-leave{ opacity:0; } .modal-scale-enter{ transform:scale(1.1); } .modal-scale-leave{ transform:scale(0.8); } </style>
外部可以由使用者自行控制,使用v-if或是v-show控制显示
z-index的控制
关于z-index的控制,需要完成以下几点
1、保证弹出框的z-index足够高能使其再最外层
2、后弹出的弹出框的z-index要比之前弹出的要高
要满足以上两点,我们需要以下代码实现
constzIndex=20141223//先预设较高值 constgetZIndex=function(){ returnzIndex++//每次获取之后zindex自动增加 }
然后绑定把z-index在组件上
<template> <divclass="modal":style="{'z-index':zIndex}"transition="modal-scale"> <!--省略其它内容--> </div> </template> <script> exportdefault{ data(){ return{ zIndex:getZIndex() } } } </script>
overlay遮盖层的控制
遮盖层是弹窗组件中最难处理的部分,一个完美的遮盖层的控制需要完成以下几点:
1、遮盖层和弹出层之间的动画需要并行
2、遮盖层的z-index要较小与弹出层
3、遮盖层的弹出时需要组件页面滚动
4、点击遮盖层需要给予弹出层反馈
5、保证整个页面最多只能有一个遮盖层(多个叠在一起会使遮盖层颜色加深)
为了处理这些问题,也保证所有的弹出框组件不用每一个都解决,所以决定利用vue的mixins机制,将这些弹出层的公共逻辑封装层一个mixin,每个弹出框组件直接引用就好。
vue-popup-mixin
明确了上述所有的问题,开始开发mixin,首先需要一个overlay(遮盖层组件);
<template> <divclass="overlay"@click="handlerClick"@touchmove="prevent":style="style"transition="overlay-fade"></div> </template> <script> exportdefault{ props:{ onClick:{ type:Function }, opacity:{ type:Number, default:0.4 }, color:{ type:String, default:'#000' } }, computed:{ style(){ return{ 'opacity':this.opacity, 'background-color':this.color } } }, methods:{ prevent(event){ event.preventDefault() event.stopPropagation() }, handlerClick(){ if(this.onClick){ this.onClick() } } } } </script> <stylelang="less"> .overlay{ position:fixed; left:0; right:0; top:0; bottom:0; background-color:#000; opacity:.4; z-index:1000; } .overlay-fade-transition{ transition:all.3slinear; &.overlay-fade-enter, &.overlay-fade-leave{ opacity:0!important; } } </style>
然后需要一个js来管理overlay的显示和隐藏。
importVuefrom'vue' importoverlayOptfrom'../overlay'//引入overlay组件 constOverlay=Vue.extend(overlayOpt) constgetDOM=function(dom){ if(dom.nodeType===3){ dom=dom.nextElementSibling||dom.nextSibling getDOM(dom) } returndom } //z-index控制 constzIndex=20141223 constgetZIndex=function(){ returnzIndex++ } //管理 constPopupManager={ instances:[],//用来储存所有的弹出层实例 overlay:false, //弹窗框打开时调用此方法 open(instance){ if(!instance||this.instances.indexOf(instance)!==-1)return //当没有遮盖层时,显示遮盖层 if(this.instances.length===0){ this.showOverlay(instance.overlayColor,instance.overlayOpacity) } this.instances.push(instance)//储存打开的弹出框组件 this.changeOverlayStyle()//控制不同弹出层透明度和颜色 //给弹出层加上z-index constdom=getDOM(instance.$el) dom.style.zIndex=getZIndex() }, //弹出框关闭方法 close(instance){ letindex=this.instances.indexOf(instance) if(index===-1)return Vue.nextTick(()=>{ this.instances.splice(index,1) //当页面上没有弹出层了就关闭遮盖层 if(this.instances.length===0){ this.closeOverlay() } this.changeOverlayStyle() }) }, showOverlay(color,opacity){ letoverlay=this.overlay=newOverlay({ el:document.createElement('div') }) constdom=getDOM(overlay.$el) dom.style.zIndex=getZIndex() overlay.color=color overlay.opacity=opacity overlay.onClick=this.handlerOverlayClick.bind(this) overlay.$appendTo(document.body) //禁止页面滚动 this.bodyOverflow=document.body.style.overflow document.body.style.overflow='hidden' }, closeOverlay(){ if(!this.overlay)return document.body.style.overflow=this.bodyOverflow letoverlay=this.overlay this.overlay=null overlay.$remove(()=>{ overlay.$destroy() }) }, changeOverlayStyle(){ if(!this.overlay||this.instances.length===0)return constinstance=this.instances[this.instances.length-1] this.overlay.color=instance.overlayColor this.overlay.opacity=instance.overlayOpacity }, //遮盖层点击处理,会自动调用弹出层的overlayClick方法 handlerOverlayClick(){ if(this.instances.length===0)return constinstance=this.instances[this.instances.length-1] if(instance.overlayClick){ instance.overlayClick() } } } window.addEventListener('keydown',function(event){ if(event.keyCode===27){//ESC if(PopupManager.instances.length>0){ consttopInstance=PopupManager.instances[PopupManager.instances.length-1] if(!topInstance)return if(topInstance.escPress){ topInstance.escPress() } } } }) exportdefaultPopupManager
最后再封装成一个mixin
importPopupManagerfrom'./popup-manager' exportdefault{ props:{ show:{ type:Boolean, default:false }, //是否显示遮盖层 overlay:{ type:Boolean, default:true }, overlayOpacity:{ type:Number, default:0.4 }, overlayColor:{ type:String, default:'#000' } }, //组件被挂载时会判断show的值开控制打开 attached(){ if(this.show&&this.overlay){ PopupManager.open(this) } }, //组件被移除时关闭 detached(){ PopupManager.close(this) }, watch:{ show(val){ //修改show值是调用对于的打开关闭方法 if(val&&this.overlay){ PopupManager.open(this) }else{ PopupManager.close(this) } } }, beforeDestroy(){ PopupManager.close(this) } }
使用
以上所有的代码就完成了所有弹出层的共有逻辑,使用时只需要当做一个mixin来加载即可
<template> <divclass="dialog" v-show="show" transition="dialog-fade"> <divclass="dialog-content"> <slot></slot> </div> </div> </template> <style> .dialog{ left:50%; top:50%; transform:translate(-50%,-50%); position:fixed; width:90%; } .dialog-content{ background:#fff; border-radius:8px; padding:20px; text-align:center; } .dialog-fade-transition{ transition:opacity.3slinear; } .dialog-fade-enter, .dialog-fade-leave{ opacity:0; } </style> <script> importPopupfrom'../src' exportdefault{ mixins:[Popup], methods:{ //响应overlay事件 overlayClick(){ this.show=false }, //响应esc按键事件 escPress(){ this.show=false } } } </script>
总结
以上就是关于vue.js弹窗组件的一些知识点,希望对大家的学习或者工作带来一定的帮助,如果大家有疑问可以留言交流,谢谢大家对毛票票的支持。