zoukankan      html  css  js  c++  java
  • Element 中的 DropDown 定位解析

    一、前言

    进来事情较少。

    今天早上在群里面有看到,对于 iview select 的下拉框定位问题的讨论。

    因为主要用的是 Element-UI,就对这一块做了深入的了解。

    二、发现问题

    如上面说的,在得到这个问题后,想到应该不只是 select 下拉所有的 dropdowm 的定位应该是一样的。

    就直接在 Element-UI 官网看下,选择了级联看了下:

    在这里看到 dropdown 是直接挂载在 body 下的。

    简单分析后得出:

    1、dropdown 是通过 absolute 进行绝对定位的;

    2、第一次点击前,没有挂载到 dom,点击后才挂载,后面是通过 display: none 控制显示

    比较好奇的就是这个绝对定位的 left、top 是怎么计算出来的?

    查了一圈,并且看了 Element-UI 源码也没有发现什么(这里是自己了解不够到位)。

    在遇到这篇文章后,才有了下面的进一步深入:Element 源码解析系列7-select

    三、底层原理

    在看了这一篇文章后,才对 popper.js 有深入了解。

    在 Element-ui 中对其做了封装在:srcutilsvue-popper.js 这里。这个的作用主要就是计算绝对定位的位置、实时改变

    下面的代码都是在源码中的 srcutilspopper.js 文件中

    1、初始化

    在 Popper 进行初始化的时候,会先对要弹出的 element 进行样式初始化,设置 postion 是 absolute 还是 fixed。

    会进行第一次 update、_setupEventListeners

    2、计算位置

    这个主要是从 update 里面找到的:

        Popper.prototype.update = function() {
            var data = { instance: this, styles: {} };
    
            // store placement inside the data object, modifiers will be able to edit `placement` if needed
            // and refer to _originalPlacement to know the original value
            data.placement = this._options.placement;
            data._originalPlacement = this._options.placement;
    
            // compute the popper and reference offsets and put them inside data.offsets
            data.offsets = this._getOffsets(this._popper, this._reference, data.placement);
    
            // get boundaries
            data.boundaries = this._getBoundaries(data, this._options.boundariesPadding, this._options.boundariesElement);
    
            data = this.runModifiers(data, this._options.modifiers);
    
            if (typeof this.state.updateCallback === 'function') {
                this.state.updateCallback(data);
            }
        };

    其中 _getOffsets 就是计算对应的偏移的

    3、实时更新位置

    _setupEventListeners 的作用是设置监听,主要有 resize 和 scroll 两个监听事件:

        Popper.prototype._setupEventListeners = function() {
            // NOTE: 1 DOM access here
            this.state.updateBound = this.update.bind(this);
            root.addEventListener('resize', this.state.updateBound);
            // if the boundariesElement is window we don't need to listen for the scroll event
            if (this._options.boundariesElement !== 'window') {
                var target = getScrollParent(this._reference);
                // here it could be both `body` or `documentElement` thanks to Firefox, we then check both
                if (target === root.document.body || target === root.document.documentElement) {
                    target = root;
                }
                target.addEventListener('scroll', this.state.updateBound);
                this.state.scrollTarget = target;
            }
        };

    就是当屏幕变化或者滚动时,会再次计算 Popper 的定位位置信息,并更新。

    4、底层解析

    开始感觉这个定位计算会不会很难什么的,在从 update 的 _getOffsets 步步找下去发现计算的代码:

        function getBoundingClientRect(element) {
            var rect = element.getBoundingClientRect();
    
            // whether the IE version is lower than 11
            var isIE = navigator.userAgent.indexOf("MSIE") != -1;
    
            // fix ie document bounding top always 0 bug
            var rectTop = isIE && element.tagName === 'HTML'
                ? -element.scrollTop
                : rect.top;
    
            return {
                left: rect.left,
                top: rectTop,
                right: rect.right,
                bottom: rect.bottom,
                 rect.right - rect.left,
                height: rect.bottom - rectTop
            };
        }

    其中 element.getBoundingClientRect() 是获取一个元素的大小以及相对视口的位置。

    看了这个后真的感觉,所有看似很复杂、牛掰的操作都是源自于最基础最底层的。

    在这里用到了 DOM API ,Element.getBoundingClientRect(),这里点击看到 MDN 上面的文档。

  • 相关阅读:
    Kubernetes 集成研发笔记
    Rust 1.44.0 发布
    Rust 1.43.0 发布
    PAT 甲级 1108 Finding Average (20分)
    PAT 甲级 1107 Social Clusters (30分)(并查集)
    PAT 甲级 1106 Lowest Price in Supply Chain (25分) (bfs)
    PAT 甲级 1105 Spiral Matrix (25分)(螺旋矩阵,简单模拟)
    PAT 甲级 1104 Sum of Number Segments (20分)(有坑,int *int 可能会溢出)
    java 多线程 26 : 线程池
    OpenCV_Python —— (4)形态学操作
  • 原文地址:https://www.cnblogs.com/zhurong/p/12564923.html
Copyright © 2011-2022 走看看