大家好,我是九幡,今天分享一个关于ElementUI Popup型组件显示层级的问题。
目录
现象
实现方式
自定义方式
案例
现象
我们平时在使用ElementUI的时候,也许会发现这样的现象:
像选择器的下拉列表、弹框、对话框、弹出框等Popup类型的组件,他们的DOM上,会通过内联样式设定z-index属性:
并且在我们每次使这些组件从不显示到显示时,它们的z-index就会累加:
并且这个用来做累加的值,是这些组件间共用的:
我们知道,z-index属性可以用来控制元素的堆叠顺序,Element的这种机制,保证了后激活的Popup组件位于更高的层级,不会被之前打开的Popup组件遮挡。那Element是如何实现的呢?
实现方式
我们通过阅读Element的源码可以发现,这些Popup组件,都会引入一个vue-popper的混入。
在vue-popper中,我们就可以看到一些设置z-index的方法:
上图中的PopupManager是vue-popper引入的一个对象。
在PopupManager中,我们可以看到这个nextZIndex方法,就是对一个zIndex变量的累加,因为导出的PopupManager对象是引用类型,所以组件间可以共享这个zIndex变量。
到这里,Element给Popup组件设置z-index的实现方式我们已经大致上了解了。
自定义方式
我们在PopupManager的代码中可以看到下面的代码片段:
因此我们知道,在我们读取zIndex时,它的值可能有3个来源:
- 在已经初始化过、即已经走过一遍zIndex的get方法时,获取本地的zIndex。
- 如果没有初始化过,则使用Vue.prototype.$ELEMENT上的zIndex属性。这个$ElEMENT,其实是我们在Vue.use Element时,传递的参数。
- 如果没有初始化,也没在use时给定z-index,则默认2000。
所以,如果我们想设定z-index的初始值,官方推荐的方式就是在引入Element时进行设置。
但有的时候,这种方式并不能满足我们的需求,我们还可以用别的方式进行设置。
案例
在对Element的Popup型组件进行封装,通过组件库方式提供给其他工程使用时,发现有的时候,组件库提供的Popup型组件会被各工程自己的Popup型组件遮挡。
通过上面的记述的实现方式,我们可以分析出原因:
1.组件库封装的Popup组件所使用的Element的组件和各工程的Element来源不同,导致它们使用了不同的PopperManager,在未设定初始z-index的情况,它们都是2000。
2.各工程在使用过程中,它们的PopperManager的z-index进行了累加。而组件库的组件在还没被使用时,组件库的PopperManager还是2000。导致各工程组件的z-index,大于组件库的z-index,出现遮挡现象。
根据上述原因,我们可以知道,如果想让组件库的Popup型组件不被各使用库的工程组件遮挡,就得让组件库Popup的z-index大于各使用库的工程的。
但我们的组件库是不会Vue.use Element的,没办法通过上面自定义设置的方式来设定z-index。
所以我们可以采取下面的方式:
我们通过手动给组件库使用的PopupManger的zIndex属性设值,使得组件库的Popup组件的z-index将从300000开始。这个数值是远超各使用工程的默认值2000的。
一般来说,这样就足够了,但细心的小伙伴们可能会发现,这个方式还是存在一定问题的,就是组件库和各使用工程的nextZIndex所使用的值,不是同一个值,这样就会导致在一些情境下(比如子工程的Popup组件真的就使用了这么多次,但其实z-index本身也是有上限的呀),还是有可能出现遮挡问题。大家可以在这个基础上进行一些改善。
比如就想实现组件库和使用工程z-index的同步,可以让使用工程把它的PopperManager传递给组件库,组件库监听使用工程的PoperManager的z-index属性,在其发生变化时,同步设置到组件库的z-index上。我相信聪明的小伙伴们通过我的抛砖,已经知道该怎么做,或者已经想到更好的方式了,我这里就不在赘述了。
以上就是本文的全部内容啦,本人能力有限,如果记述有误,还请您留言指出,感谢谅解和支持。
如果您有更好的想法和建议,欢迎留言评论!如果这篇文章有帮助到您,希望您能为本篇文章点个赞!