Отличный способ узнать, имеет ли элемент или какой-либо из его родительских элементов отображение: нет - PullRequest
0 голосов
/ 29 октября 2018

Мне нужно найти очень эффективный способ выяснить, имеет ли пользовательский элемент или какой-либо из его родительских элементов display: none;

Первый подход:

checkVisible() {
  let parentNodes = [];
  let el = this;
  while (!!(el = el.parentNode)) {
    parentNodes.push(el);
  }
  return [this, ...parentNodes].some(el => el.style.display === 'none') 
}

Есть ли что-нибудь, что работает быстрее этого? Это даже безопасный метод?

Причина, по которой мне это нужно: у нас есть <data-table> пользовательский элемент (собственный веб-компонент), который очень тяжело поднимается в connectedCallback(). У нас есть приложение, содержащее около 20-30 таких пользовательских элементов на одной странице, что приводит к тому, что IE 11 занимает около 15 секунд до визуализации страницы.

Мне нужно отложить инициализацию тех <data-table> компонентов, которые изначально даже не видны, поэтому мне нужен способ проверить внутри connectedCallback(), видим ли элемент (чего нет, если он находится в одном из 18 вкладок изначально не показаны).

Ответы [ 2 ]

0 голосов
/ 30 октября 2018

Самый простой способ узнать, есть ли у элемента или его родителя display:none, это использовать el.offsetParent.

const p1 = document.getElementById('parent1');
const p2 = document.getElementById('parent2');
const c1 = document.getElementById('child1');
const c2 = document.getElementById('child2');
const btn = document.getElementById('btn');
const output = document.getElementById('output');

function renderVisibility() {
  const p1state = isElementVisible(p1) ? 'is visible' : 'is not visible';
  const p2state = isElementVisible(p2) ? 'is visible' : 'is not visible';
  const c1state = isElementVisible(c1) ? 'is visible' : 'is not visible';
  const c2state = isElementVisible(c2) ? 'is visible' : 'is not visible';
  
  output.innerHTML = `Parent 1 ${p1state}<br>Parent 2 ${p2state}<br/>Child 1 ${c1state}<br/>Child 2 ${c2state}`;
}

function isElementVisible(el) {
  return !!el.offsetParent;
}

function toggle() {
  p1.style.display = (p1.style.display ? '' : 'none');
  p2.style.display = (p2.style.display ? '' : 'none');
  renderVisibility();
}

btn.addEventListener('click', toggle),
renderVisibility();
<div id="parent1" style="display:none">
  <div id="child1">child 1</div>
</div>
<div id="parent2">
  <div id="child2">second child</div>
</div>
<button id="btn">Toggle</button>
<hr>
<div id="output"></div>

Этот код преобразует el.offsetParent в логическое значение, которое указывает, отображается элемент или нет.

Это работает только для display:none

0 голосов
/ 29 октября 2018

Не уверен насчет производительности, но она должна быть как минимум быстрее вашего подхода:

HTMLElement.prototype.isInvisible = function() {
  if (this.style.display == 'none') return true;
  if (getComputedStyle(this).display === 'none') return true;
  if (this.parentNode.isInvisible) return this.parentNode.isInvisible();
  return false;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...