如何获得iframe相对于顶部窗口的位置's视口

How to get the position of an iframe relative to the top window's viewport?

本文关键字:视口 位置 iframe 何获得 相对于 顶部 窗口      更新时间:2023-09-26

我有这样的html:

<body>
    [some stuff]
    <iframe src="pageWithMyScript.html"></iframe>
    [more stuff]
</body>

我想从iframe内部运行的脚本中找到iframe相对于window.top(和/或top.docent)的位置。(理想情况下,这将没有任何框架,尽管我想我总是可以解构它们是如何做到的。)

只有当iframe和容器共享同一来源时,这才能工作,否则必须设置CORS(要做到这一点,您需要访问两个域)

/**
 * Calculate the offset of the given iframe relative to the top window.
 * - Walks up the iframe chain, checking the offset of each one till it reaches top
 * - Only works with friendly iframes. https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Cross-origin_script_API_access 
 * - Takes into account scrolling, but comes up with a result relative to 
 *   top iframe, regardless of being visibile withing intervening frames.
 * 
 * @param window win    the iframe we're interested in (e.g. window)
 * @param object dims   an object containing the offset so far:
 *                          { left: [x], top: [y] }
 *                          (optional - initializes with 0,0 if undefined) 
 * @return dims object above
 */
var computeFrameOffset = function(win, dims) {
    // initialize our result variable
    if (typeof dims === 'undefined') {
        var dims = { top: 0, left: 0 };
    }
    // find our <iframe> tag within our parent window
    var frames = win.parent.document.getElementsByTagName('iframe');
    var frame;
    var found = false;
    for (var i=0, len=frames.length; i<len; i++) {
        frame = frames[i];
        if (frame.contentWindow == win) {
            found = true;
            break;
        }
    }
    // add the offset & recur up the frame chain
    if (found) {
        var rect = frame.getBoundingClientRect();
        dims.left += rect.left;
        dims.top += rect.top;
        if (win !== top) {
            computeFrameOffset(win.parent, dims);
        }
    }
    return dims;
};

像这样简单一点:

function computeFrameOffset(win, dims ) {
    dims = (typeof dims === 'undefined')?{ top: 0, left: 0}:dims;
    if (win !== top) {
        var rect = win.frameElement.getBoundingClientRect();
        dims.left += rect.left;
        dims.top += rect.top;
        computeFrameOffset(win.parent, dims );
    }
    return dims;
};

一个小的修正:

function computeFrameOffset(win, dims ) {
  dims = (typeof dims === 'undefined')?{ top: 0, left: 0}:dims;
  if (win !== top) {
      var rect = win.frameElement.getBoundingClientRect();
      dims.left += rect.left;
      dims.top += rect.top;
      dims = computeFrameOffset(win.parent, dims ); // recursion
  }
  return dims;
};

大多数答案都不考虑框架元素的边框和填充
有时它们不是0,所以它应该包含在转换过程中
元素的实际边界和填充大小可以从";"计算风格";。

    function getTopBoundingClientRect( e )
    {
        const rcInit = e.getBoundingClientRect();
        let f = e.ownerDocument.defaultView.frameElement;
        if ( !f )
            return rcInit;
        const rc = { left: rcInit.left, top: rcInit.top, right: rcInit.right, bottom: rcInit.bottom };
        do {
            const frc = f.getBoundingClientRect();
            const cs = f.ownerDocument.defaultView.getComputedStyle( f );
            const lm = +cs.getPropertyValue( 'border-left-width' ).slice( 0, -2 )
                + +cs.getPropertyValue( 'padding-left' ).slice( 0, -2 );
            const tm = +cs.getPropertyValue( 'border-top-width' ).slice( 0, -2 )
                + +cs.getPropertyValue( 'padding-top' ).slice( 0, -2 );
            rc.left += frc.left + lm;
            rc.top += frc.top + tm;
            rc.right += frc.left + lm;
            rc.bottom += frc.top + tm;
            f = f.ownerDocument.defaultView.frameElement;
        } while ( f );
        return rc;
    }

当然,在跨域iframe中,任何代码都不能访问父文档(尤其是上面代码中的frameElement)。