开发者

How can I get these jQuery results with vanilla JavaScript?

开发者 https://www.devze.com 2023-02-04 00:19 出处:网络
Does anyb开发者_开发问答ody know how I can get the equivalent of jQuery\'s .offset() and .closest() without a JavaScript library?

Does anyb开发者_开发问答ody know how I can get the equivalent of jQuery's .offset() and .closest() without a JavaScript library?

For .closest(), if I know how far to climb up the DOM tree, I can just use that many .parentNodes, but if I don't know how far to go, I'm stuck.


jQuery is javascript at its core. You can use this jQuery source viewer to find out implementation of any method.

For example, here is how closest is implemented:

closest: function( selectors, context ) {
    var ret = [], i, l, cur = this[0];

    if ( jQuery.isArray( selectors ) ) {
        var match, selector,
            matches = {},
            level = 1;

        if ( cur && selectors.length ) {
            for ( i = 0, l = selectors.length; i < l; i++ ) {
                selector = selectors[i];

                if ( !matches[selector] ) {
                    matches[selector] = jQuery.expr.match.POS.test( selector ) ? 
                        jQuery( selector, context || this.context ) :
                        selector;
                }
            }

            while ( cur && cur.ownerDocument && cur !== context ) {
                for ( selector in matches ) {
                    match = matches[selector];

                    if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) {
                        ret.push({ selector: selector, elem: cur, level: level });
                    }
                }

                cur = cur.parentNode;
                level++;
            }
        }

        return ret;
    }

    var pos = POS.test( selectors ) ? 
        jQuery( selectors, context || this.context ) : null;

    for ( i = 0, l = this.length; i < l; i++ ) {
        cur = this[i];

        while ( cur ) {
            if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
                ret.push( cur );
                break;

            } else {
                cur = cur.parentNode;
                if ( !cur || !cur.ownerDocument || cur === context ) {
                    break;
                }
            }
        }
    }

    ret = ret.length > 1 ? jQuery.unique(ret) : ret;

    return this.pushStack( ret, "closest", selectors );
}

And here is the implementation of the offset:

jQuery.fn.offset = function( options ) {
    var elem = this[0], box;

    if ( options ) { 
        return this.each(function( i ) {
            jQuery.offset.setOffset( this, options, i );
        });
    }

    if ( !elem || !elem.ownerDocument ) {
        return null;
    }

    if ( elem === elem.ownerDocument.body ) {
        return jQuery.offset.bodyOffset( elem );
    }

    try {
        box = elem.getBoundingClientRect();
    } catch(e) {}

    var doc = elem.ownerDocument,
        docElem = doc.documentElement;

    // Make sure we're not dealing with a disconnected DOM node
    if ( !box || !jQuery.contains( docElem, elem ) ) {
        return box || { top: 0, left: 0 };
    }

    var body = doc.body,
        win = getWindow(doc),
        clientTop  = docElem.clientTop  || body.clientTop  || 0,
        clientLeft = docElem.clientLeft || body.clientLeft || 0,
        scrollTop  = (win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop ),
        scrollLeft = (win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft),
        top  = box.top  + scrollTop  - clientTop,
        left = box.left + scrollLeft - clientLeft;

    return { top: top, left: left };
};


Why not use a library? I suppose there might be a reason for writing your own, but it probably won't be as good as jQuery's.

My crappy little five-minute implementation of offset looks like:

function getOffset(elem) {
    var offset = null;
    if ( elem ) {
        offset = {left: 0, top: 0};
        do {
            offset.top += elem.offsetTop;
            offset.left += elem.offsetLeft;
            elem = elem.offsetParent;
        } while ( elem );
    }
    return offset;
}


The easiest way to walk up a tree that's n deep, where you don't know n is recursion, and not looping. Then again walking up a tree without knowing it's root seems like a bizarre situation and not one you are likely to encounter when walking the DOM.

At some point you will hit the body tag and then you have nowhere left to go, unless you are inside an iframe in which case you want to be looking for the top window and finds it's document.body


Read source of jQuery:

For the .closest() you can make a loop over parentNode and stop where your next parent is equal to window.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号