• 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 上面的文档。

  • 相关阅读:
    HDU1536_SNim_求sg值
    HDU1851_A Simple Game_求sg
    POJ1067_取石子游戏_威佐夫博弈
    HDU1848_Fibonacci again and again_经典的求sg
    POJ2425 && HDU1524_ A Chess Game_树形博弈
    .GB级数据库分区实现高性能
    数据库锁
    热烈庆祝“mysql 集群数据库架构成功”
    linux mysql注意事项
    SQL Server 数据库做读写分离
  • 原文地址:https://www.cnblogs.com/zhurong/p/12564923.html
Copyright © 2020-2023  润新知