getBoundingClientRect из iFrame

У меня есть функция для оценки того, находится ли элемент (iFrame) в области просмотра, если элемент находится в поле зрения, он возвращает true.

function isElementInViewport() {
    var el = document.getElementById('postbid_if')
    var rect = el.getBoundingClientRect();
    var elemTop = rect.top;
    var elemBottom = rect.bottom;

    console.log("eleTom " + elemTop)
    console.log("elemBottom " + elemBottom)
    console.log("window.innerHeight " + (window.innerHeight + (window.top.innerHeight * 0.5)))

    var isVisible = (elemTop >= 0) && (elemBottom <= (window.innerHeight + window.innerHeight * 0.5));
    return isVisible;
}

Эта функция работает правильно, когда обслуживается непосредственно на странице, но в реальной среде, когда эта функция запускается, она находится внутри iFrame, и похоже, что getBoundingClientRect() ссылается на область просмотра iFrame, а не на главное окно?

Есть ли способ использовать окно просмотра главного окна из iFrame с getBoundingClientRect()


person Jonathan Devereux    schedule 30.10.2018    source источник


Ответы (1)


Каждый iframe имеет свою область действия, поэтому окно внутри iframe отличается от корневого окна.

Вы можете получить корневое окно с помощью window.top, и с учетом этого вы можете рассчитать абсолютную позицию текущего iframe. Вот правильная функция:

function currentFrameAbsolutePosition() {
  let currentWindow = window;
  let currentParentWindow;
  let positions = [];
  let rect;

  while (currentWindow !== window.top) {
    currentParentWindow = currentWindow.parent;
    for (let idx = 0; idx < currentParentWindow.frames.length; idx++)
      if (currentParentWindow.frames[idx] === currentWindow) {
        for (let frameElement of currentParentWindow.document.getElementsByTagName('iframe')) {
          if (frameElement.contentWindow === currentWindow) {
            rect = frameElement.getBoundingClientRect();
            positions.push({x: rect.x, y: rect.y});
          }
        }
        currentWindow = currentParentWindow;
        break;
      }
  }
  return positions.reduce((accumulator, currentValue) => {
    return {
      x: accumulator.x + currentValue.x,
      y: accumulator.y + currentValue.y
    };
  }, { x: 0, y: 0 });
}

Теперь внутри isElementInViewport измените эти строки:

var elemTop = rect.top;
var elemBottom = rect.bottom;

to

var currentFramePosition = getCurrentFrameAbsolutePosition();
var elemTop = rect.top + currentFramePosition.y;
var elemBottom = rect.bottom + currentFramePosition.y;

и это должно работать.

person pawelbylina    schedule 20.12.2018
comment
ofc, это не относится к безопасным фреймам, так как у вас нет доступа к родительским окнам - person Gena Moroz; 01.02.2021
comment
Да, это правда. И нет никакой другой возможности сделать это. - person pawelbylina; 01.02.2021