热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

『你不知道的ElementUI』被隐藏的神级组件:Popper和它的管家

『你不知道的ElementUI』被隐藏的神级组件:Popper和它的管家-阅读本文?你将:认识两个ElementUI官方文档没有记载,但实际已经被内置的组件。学会使用它们


阅读本文?

你将:



  • 认识两个 ElementUI 官方文档没有记载,但实际已经被内置的组件。

  • 学会使用它们,并获得 demo 一份。

  • 了解 ElementUI 弹出层组件的基本原理,以后面对要不要 appendToBody 及相关问题成竹于胸。


『你不知道的ElementUI』系列

本系列将会深入 ElementUI,为你提供一些只有 ElementUI 资深使用者甚至代码贡献者才会知道的『神级知识』。
它们无论是在日常工作使用中,或是在面试装哔时,都非常实用。
另外:本系列也适合 Element Plus 的用户观看,因为 Element 的核心原理没有大的变化。


一、ElementUI 里所有弹出层的两种模式

ElementUI 的弹出层(包括但不限于:dialog, select, popover, date-picker 等)在元素定位上,都有两种实现方式,分别是:



  • 方案一: append-to-body 式。此模式下,弹出层会被放在 元素上,通过 position:fixed 定位,配合动态的 topleft 属性,完成弹出元素的定位。

  • 方案二: 非 append-to-body 式。此模式下,弹出层通过 position:absolute 定位,配合其父元素 position:relative 来完成弹出元素的定位。

在大多数情况下, ElementUI 都是默认使用的 『方案一:append-to-body 式』。
原因很简单,因为『方案二: 非 append-to-body 式』 存在严重副作用,只有迫不得已的情况下才需要使用。

例如,当弹出层组件的父元素拥有 position: relative; overflow: auto 样式时,是否 append-to-body 可能直接影响组件的显示:

示例代码:https://github.com/zhangshichun/blog-vue2-demos/tree/master/src/views/about-append-to-body


为什么『非 append-to-body 模式』会导致这个问题,而『append-to-body 模式』则不会?这是一道css基础题,欢迎把你的理解打在评论里。


除了上述场景,『非 append-to-body 模式』还会在多种场景下导致类似的问题。

这也是为什么 ElementUI 会把所有弹出层设置为『append-to-body 模式』的根本原因。


二、ElementUI 是如何管理弹出层的z-index的?

第一节已经聊到了,除非特别指定,ElementUI 都会自动使用 『append-to-body 模式』来进行弹出层的实现。
在这个前提下,不妨假象自己是 ElementUI 的开发人员,你会怎么实现以下效果:



  • 应该如何保证 dialog 组件里,select 组件的弹出层高于 dialog 的弹出层?

  • 应该如何保证 dialog-1 上再次弹出的 dialog-2 的层级高于 dialog-1的层级?

ElementUI 项目组的人员在设计这块的时候,想出了一个简单却让人拍案叫绝的办法:只要让新出现的弹出层,永远比之前所有弹出层的层级要高,就不会有『新弹层』被『旧弹层』遮盖的事情发生。

假设一个场景:“弹窗-1”上点击某个按钮弹出“弹窗-2”,而“弹窗-2”上又有个“下拉框组件”,此时它们的 z-index 会是什么样的呢?

如上图所示,只要保证每次“弹出层”在弹出时,都在当前最大 z-index 的基础上 +1,就可以保证没有弹出层会被无故挡住。

记住这个机制,它是 ElementUI 弹出层的核心实现机制。

那么,又是有谁来管理整个项目的 z-index 的呢?

当然是—— popup管家 啦~


三、认识:老管家(PopupManager)


当蝙蝠侠在哥谭市和形形色色的反派殊死搏斗时,他的老管家阿福总能帮他将后方安排得妥妥贴贴。


ElementUI 里,所有弹出层的背后,都有这样一位辛勤的老管家,它就是 PopupManager

PopupManager: 为弹出层提供获取实例、注册、注销 等各种能力,但其最重要的能力,是提供了 z-index 的层级管理能力。

如何使用它?


效果如下:

发现没,第一次 PopupManager.nextZIndex() 会返回2000,然后每次点击都会 +1

后续的 +1 很好理解,每次弹出层要获取到的最新可用 z-index 就是要比之前的那一层多 1

但是为什么一开始会是 2000 呢?

其实这是 ElementUI 内置的一个“弹出层 z-index 基数”,但它是可以进行修改的。

在安装 ElementUI 时,通过以下代码可以让内置的 2000 变成 3000

// 这可以让弹出层的 z-index 从 3000 开始递增
Vue.use(Element, { zIndex: 3000 });

认识老管家的作用,不仅仅是理解 ElementUIz-index 管理机制那么简单,它在实际生产和项目中也可以非常有用。

示例代码:https://github.com/zhangshichun/blog-vue2-demos/tree/master/src/views/popup-manager


四、实战:一个更灵活的全屏组件


官方全屏API虽然好,但产品经理说官方不懂业务。


众所周知,浏览器是有官方的全屏API的:Element.requestFullscreen() ,它可以让一个元素立刻铺满视窗,并且置于所有元素之上。

虽然,这是个看起来很美的 API,但架不住产品经理总有一些奇葩的要求:“这个页面支持全屏,然后它上面还要有一些弹窗,弹窗里面是一些复杂的表单....”

当时听到这我就麻了:


“官方全屏是设定层面的高于一切,那些 append-to-body的弹窗,无论 z-index 再高,也绝对不可能被显示出来。”



“而那些非 append-to-body 模式的弹出层,确实会在某些业务场景不符合要求。)”


左思右想,还得封装一个“符合 ElementUI 层级标准的全屏组件”。

思路很简单:

和浏览器官方API实现全屏的思路基本一致,但不同的地方在于:



  • 官方全屏会默认置顶,z-index无限大

  • 自己封装的全屏,z-index符合 PopupManager 管家的规范。

因此我写了一个简陋的二十几行的 demo


效果上和浏览器官方API进行了对比:

虽然效果上肯定比不了官方的直接全屏,自行封装的还必须配合手动 F11,但完全印证了一个问题:

PopupManager 完全可以用于生产,解决实际问题。

示例代码:https://github.com/zhangshichun/blog-vue2-demos/tree/master/src/views/full-screen


五、认识:万能弹出组件(vue-popper)


虽然管家阿福很厉害,但蝙蝠侠不能骑着阿福去战斗。于是有了蝙蝠战车。


vue-popper 的就是这辆“蝙蝠战车”。一点也不夸张。
我们所能接触到的,ElementUI 中的大部分弹出层都是基于 vue-popper 组件来实现的。

简单罗列一下:selectdate-picker族级联cascaderdropdownpopovertooltip...等等,这些组件都是基于 vue-popper 组件来实现弹出层的。

那么 vue-popper 要怎么使用呢?

通常来说,它的主要用法是 混入(mixins)。使用起来三步走:

最典型的例子,代码太多我就不列了,可以看看 ElementUI dropdown-menu 里对它的具体使用。代码见:https://github.com/ElemeFE/element/blob/dev/packages/dropdown/src/dropdown-menu.vue

混入的例子太复杂,有没有不用混入,直接把它当做组件的用法呢?

当然有!


五、实战:完全自定义的弹出层

如何使用 vue-popper 编写一个简单的“自定义弹出层”的 demo

按照以下三步即可:



  1. 首先我们引入 vue-popper,在模板中引用该组件,并定义一个弹出层元素,一个定位元素。



    2. 给 `vue-popper` 实例指定**弹出层**和**定位层**。
    ```Javascript
    mounted() {
    this.$refs.popper.popperElm = this.$refs['fly-piece'];
    this.$refs.popper.referenceElm = this.$el;
    }


    1. 通过控制 vue-popperprops.value 来控制是否弹出。

      this.showPopper = !this.showPopper

      就能实现如下效果:



    是不是很简单?

    有了这个组件,当你想实现一些自定义的复杂组件的时,是不是很实用?

    示例代码:https://github.com/zhangshichun/blog-vue2-demos/tree/master/src/views/my-picker


    总结

    ok,让我们回忆一下,本文我们讲了哪些知识点:



    1. ElementUI 弹出层的两种模式,以及它们的实现原理。

    2. ElementUI 如何管理弹出层的 z-index

    3. PopupManager 的用法及实战。

    4. vue-popper 的用法及实战。




推荐阅读
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 解决VS写C#项目导入MySQL数据源报错“You have a usable connection already”问题的正确方法
    本文介绍了在VS写C#项目导入MySQL数据源时出现报错“You have a usable connection already”的问题,并给出了正确的解决方法。详细描述了问题的出现情况和报错信息,并提供了解决该问题的步骤和注意事项。 ... [详细]
  • 本文详细介绍了MySQL表分区的创建、增加和删除方法,包括查看分区数据量和全库数据量的方法。欢迎大家阅读并给予点评。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • Oracle10g备份导入的方法及注意事项
    本文介绍了使用Oracle10g进行备份导入的方法及相关注意事项,同时还介绍了2019年独角兽企业重金招聘Python工程师的标准。内容包括导出exp命令、删用户、创建数据库、授权等操作,以及导入imp命令的使用。详细介绍了导入时的参数设置,如full、ignore、buffer、commit、feedback等。转载来源于https://my.oschina.net/u/1767754/blog/377593。 ... [详细]
  • 深度学习中的Vision Transformer (ViT)详解
    本文详细介绍了深度学习中的Vision Transformer (ViT)方法。首先介绍了相关工作和ViT的基本原理,包括图像块嵌入、可学习的嵌入、位置嵌入和Transformer编码器等。接着讨论了ViT的张量维度变化、归纳偏置与混合架构、微调及更高分辨率等方面。最后给出了实验结果和相关代码的链接。本文的研究表明,对于CV任务,直接应用纯Transformer架构于图像块序列是可行的,无需依赖于卷积网络。 ... [详细]
  • 在springmvc框架中,前台ajax调用方法,对图片批量下载,如何弹出提示保存位置选框?Controller方法 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • 在IDEA中运行CAS服务器的配置方法
    本文介绍了在IDEA中运行CAS服务器的配置方法,包括下载CAS模板Overlay Template、解压并添加项目、配置tomcat、运行CAS服务器等步骤。通过本文的指导,读者可以轻松在IDEA中进行CAS服务器的运行和配置。 ... [详细]
  • 判断编码是否可立即解码的程序及电话号码一致性判断程序
    本文介绍了两个编程题目,一个是判断编码是否可立即解码的程序,另一个是判断电话号码一致性的程序。对于第一个题目,给出一组二进制编码,判断是否存在一个编码是另一个编码的前缀,如果不存在则称为可立即解码的编码。对于第二个题目,给出一些电话号码,判断是否存在一个号码是另一个号码的前缀,如果不存在则说明这些号码是一致的。两个题目的解法类似,都使用了树的数据结构来实现。 ... [详细]
  • 在搜索数据库中的数据时,您可以使用SQL通配符。SQL通配符在搜索数据库中的数据时,SQL通配符可以替代一个或多个字符。SQL通配符必须与LIKE运算符 ... [详细]
  • EzPP 0.2发布,新增YAML布局渲染功能
    EzPP发布了0.2.1版本,新增了YAML布局渲染功能,可以将YAML文件渲染为图片,并且可以复用YAML作为模版,通过传递不同参数生成不同的图片。这个功能可以用于绘制Logo、封面或其他图片,让用户不需要安装或卸载Photoshop。文章还提供了一个入门例子,介绍了使用ezpp的基本渲染方法,以及如何使用canvas、text类元素、自定义字体等。 ... [详细]
  • 本文介绍了一种求解最小权匹配问题的方法,使用了拆点和KM算法。通过将机器拆成多个点,表示加工的顺序,然后使用KM算法求解最小权匹配,得到最优解。文章给出了具体的代码实现,并提供了一篇题解作为参考。 ... [详细]
author-avatar
烧饼来一个则_815
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有