原生js实现offset方法

作者: 前端沐先生 | 来源:发表于2017-06-15 11:57 被阅读135次

    @拭目以待:首发于原生js实现offset方法

    在为 jTool 提供 offset (获取当前节点位置)方法时, 先后使用了两种方式进行实现, 现整理出来以作记录。

    前后共使用了两种方式实现了该方法, 这里将这两种方法分别列出。

    通过递归实现

    function offset(element) {
        var offest = {
            top: 0,
            left: 0
        };
     
        var _position;
     
        getOffset(element, true);
     
        return offest;
     
        // 递归获取 offset, 可以考虑使用 getBoundingClientRect
        function getOffset(node, init) {
            // 非Element 终止递归
            if (node.nodeType !== 1) {
                return;
            }
            _position = window.getComputedStyle(node)['position'];
     
            // position=static: 继续递归父节点
            if (typeof(init) === 'undefined' && _position === 'static') {
                getOffset(node.parentNode);
                return;
            }
            offest.top = node.offsetTop + offest.top - node.scrollTop;
            offest.left = node.offsetLeft + offest.left - node.scrollLeft;
     
            // position = fixed: 获取值后退出递归
            if (_position === 'fixed') {
                return;
            }
     
            getOffset(node.parentNode);
        }
    }
    
    // 执行offset
    var s_kw_wrap = document.querySelector('#s_kw_wrap');
    offset(s_kw_wrap);  // => Object {top: 181, left: 400}
    

    通过ClientRect实现

    function offset2(node) {
        var offest = {
            top: 0,
            left: 0
        };
        // 当前为IE11以下, 直接返回{top: 0, left: 0}
        if (!node.getClientRects().length) {
            return offest;
        }
        // 当前DOM节点的 display === 'node' 时, 直接返回{top: 0, left: 0}
        if (window.getComputedStyle(node)['display'] === 'none') {
            return offest;
        }
        // Element.getBoundingClientRect()方法返回元素的大小及其相对于视口的位置。
        // 返回值包含了一组用于描述边框的只读属性——left、top、right和bottom,单位为像素。除了 width 和 height 外的属性都是相对于视口的左上角位置而言的。
        // 返回如{top: 8, right: 1432, bottom: 548, left: 8, width: 1424…}
        offest = node.getBoundingClientRect();
        var docElement = node.ownerDocument.documentElement;
        return {
            top: offest.top + window.pageYOffset - docElement.clientTop,
            left: offest.left + window.pageXOffset - docElement.clientLeft
        };
    }
    
    // 执行offset
    var s_kw_wrap = document.querySelector('#s_kw_wrap');
    offset2(s_kw_wrap);  // => Object {top: 181.296875, left: 399.5}
    

    *offset2() *函数中使用到了 .getClientRects() .getBoundingClientRect() 方法,IE11 以下浏览器并不支持; 所以该种实现, 只适于现代浏览器。

    • **.getClientRects() **

      返回值是 ClientRect 对象集合(与该元素相关的CSS边框),每个 ClientRect 对象包含一组描述该边框的只读属性——left、top、right 和 bottom,单位为像素,这些属性值是相对于视口的top-left的。
      并包含 length 属性, IE11以下可以通过是否包含 length 来验证当前是否为IE11以上版现。

    • .getBoundingClientRect()

      返回值包含了一组用于描述边框的只读属性——left、top、right 和 bottom,单位为像素。除了 width 和 height 外的属性都是相对于视口的左上角位置而言的。

    • .getBoundingClientRect() 与 .getClientRects()的关系

    1. 这两个方法的区别与当前的 display 相关, 当 display=inline 时, .getClientRects() 返回当前节点内每一行文本的 ClientRect 对象数组, 此时数组长度等于文本行数。

    2. 当 display != inline 时, .getClientRects() 返回当前节点的 ClientRect 对象数组,此时数组长度为1.

    3. .getBoundingClientRect() 总是返回当前节点的 ClientRect 对象, 注意这里是 ClientRect 对象而不是对象数组。

    相关API
    getClientRects
    getBoundingClientRect

    提示
    以上测试, 可以通过在百度首页执行进行测试, document.querySelect('#s_kw_wrap') 所获取到的节点为百度首页输入框

    @拭目以待

    个人站点:www.lovejavascript.com
    表格管理插件:gridmanager.lovejavascript.com && github地址
    QQ交流群 (452781895):How To Make Love

    《野生前端工程师》专辑中所有文章均为@拭目以待 原创,转载请注明出处。

    相关文章

      网友评论

        本文标题:原生js实现offset方法

        本文链接:https://www.haomeiwen.com/subject/wybyqxtx.html