Наблюдатель пересечений с отложенной загрузкой

я хочу добиться такого поведения из этого примера с изображениями https://codepen.io/ryanfinni/pen/jONBEdX. Единственная разница заключается в том, что вместо переключения видимости img для каждого div, который он находится в поле зрения, я хочу вызвать конечную точку, чтобы получить данные и сформировать html, отправив соответствующий идентификатор данных в качестве параметра.

то, что у меня есть, работает только для первого элемента. как я могу заставить его работать для всех элементов, которые у меня есть, и нацеливать их по идентификатору данных, как в этом примере с data.src

function handleIntersection(entries) {
  entries.map((entry) => {
    if (entry.isIntersecting) {
      entry.target.src = entry.target.dataset.src;
      entry.target.classList.add('loaded')
      observer.unobserve(entry.target);
    }
  });
}

вот мой код

const LIST = document.querySelector('.city-list');
async function getData() {
  try {
    let response = await fetch('https://raw.githubusercontent.com/ashes27/infinite/master/ids.json');
    if (response.status == 200) {
      let data = await response.json();
      return data;
    } else {
      throw new Error(response.status);
    }
  } catch (error) {
    console.log(error);
  }
}

getData().then((data) => {
  for (const details in data.data.items) {
    const LI = document.createElement('li');
    const TITLE = document.createElement('h2');
    TITLE.className = 'city-title';
    TITLE.innerText = data.data.items[details].title;
    LI.appendChild(TITLE);
    LIST.appendChild(LI);
    for (const id in data.data.items[details].ids) {
      const DIV = document.createElement('div');
      DIV.setAttribute('data-id', data.data.items[details].ids[id]);
      DIV.className = 'wrapper';
      const markup = `
       <div class="city-wrapper" >
          <div class="result-wrapper">
            <div class="image-wrapper">
              <img src=""/>
            </div>
            <div class="content-wrapper">
              <div class="content-info">
                <div class="info-wrapper">
                  <h2></h2>
                  <span class="address"></span>
                </div>
              </div>
              <p class="description"></p>
              </div>
            </div>
          </div>
        </div>
      `;
      DIV.innerHTML = markup;
      LI.appendChild(DIV);
    }
  }
});

var observer = new IntersectionObserver(
  function (entries) {
    if (entries[0].isIntersecting === true) {
      observer.unobserve(document.querySelector('.city-list'));
      const getInfo = async function (post) {
        let infoResponse = await fetch('https://raw.githubusercontent.com/ashes27/infinite/master/single-item.json');
        let info = await infoResponse.json();
        return info;
      };
      getInfo().then((info) => {
        console.log(info);
        let itemsInfo = info.data.items;
        const DIV = LIST.querySelector('.wrapper');
        console.log(DIV);
        const markup = `
        <div class="city-wrapper" >
          <div class="result-wrapper">
            <div class="image-wrapper">
              <img src="${itemsInfo.mainImgUrl}"/>
            </div>
            <div class="content-wrapper">
              <div class="content-info">
                <div class="info-wrapper">
                  <h2>${itemsInfo.visitTitle}</h2>
                  <span class="address">${itemsInfo.address}</span>
                </div>
              </div>
              <p class="description">${itemsInfo.mainDescription}</p>
              </div>
            </div>
          </div>
        </div>
        `;
        DIV.innerHTML = markup;
      });
    }
  },
  { threshold: [0] }
);

observer.observe(document.querySelector('.city-list'));
.city-wrapper {
  height: 440px;
}

img {
  width: 400px;
}
 <div style="height: 400px;"></div>
  <div style="height: 400px;"></div>
  <div style="height: 400px;"></div>
  <div style="height: 400px;"></div>
  <div style="height: 400px;"></div>
  <div style="height: 400px;"></div>
  <div style="height: 400px;"></div>
  <div style="height: 400px;"></div>

  <ul class="city-list">
  </ul>

заранее спасибо!


person coder    schedule 31.07.2020    source источник
comment
Вы указали своему наблюдателю пересечение .city-list с окном просмотра. Но вы хотите знать, когда какой-либо из li элементов в списке станет (или вот-вот станет) видимым.   -  person Andreas    schedule 31.07.2020
comment
Почему [0] за порог? 0 - значение по умолчанию, и вам не нужен массив, если есть только одно значение   -  person Andreas    schedule 31.07.2020
comment
но как я могу это сделать по идентификатору данных каждого div?   -  person coder    schedule 31.07.2020
comment
Добавьте <li> к наблюдателю вместо <ul>   -  person Andreas    schedule 31.07.2020
comment
ничего не решает   -  person coder    schedule 31.07.2020


Ответы (1)


Вы сказали своему наблюдателю следить за пересечение .city-list с окном просмотра. Но вы хотите знать, когда какой-либо из элементов .wrapperdata-id) в списке станет (или вот-вот станет) видимым.

Поэтому вам необходимо .observe() эти div.wrapper элементы, а не полный список:

observer.observe(DIV);

Чтобы удалить элемент, который только что стал видимым, вы должны использовать свойство target текущего _ 8_:

observer.unobserve(entries[0].target);

data-id, который вы ищете, также доступен через то же свойство:

const dataId = entries[0].target.dataset.id;

Поскольку мы собираемся наблюдать за несколькими элементами, мы должны соответствующим образом скорректировать логику:

entries.forEach(entry => {
  // ...
});

Полный, но немного сокращенный (фиктивные данные, без getInfo()) пример:

const observer = new IntersectionObserver(
  function (entries) {
    entries.forEach(entry => {
      if (entry.isIntersecting === true) {
        observer.unobserve(entry.target); // remove the current item from the "watchlist"
        console.log(entry.target.dataset.id); // the id you're looking for
      }
    });
  },
  { threshold: [0] }
);

async function getData() {
  // dummy data
  return Promise.resolve({
    data: {
      items: {
        city1: { title: "City 1", ids: [1, 2, 3] },
        city2: { title: "City 2", ids: [4, 5, 6] }
      }
    }
  })
};

getData().then((data) => {
  const LIST = document.querySelector('.city-list');
  
  for (const details in data.data.items) {
    const LI = document.createElement('li');
    
    const TITLE = document.createElement('h2');
    TITLE.className = 'city-title';
    TITLE.innerText = data.data.items[details].title;
    LI.appendChild(TITLE);
    
    LIST.appendChild(LI);
    
    for (const id in data.data.items[details].ids) {
      const DIV = document.createElement('div');
      DIV.setAttribute('data-id', data.data.items[details].ids[id]);
      DIV.className = 'wrapper';
      
      const markup = `<div class="city-wrapper" >...</div>`;
      
      DIV.innerHTML = data.data.items[details].ids[id] + "<br />" /* so the ID is directly visible */ + markup;
      LI.appendChild(DIV);
      
      observer.observe(DIV); // add the current DIV to the "watchlist"
    }
  }
});
.city-wrapper { height: 440px; }
img { width: 400px; }
<ul class="city-list"></ul>

Или здесь: https://jsfiddle.net/sDSJrPqw/L0wd6kja/5/

person Andreas    schedule 31.07.2020
comment
Я только что увидел что-то, что не работает нормально. если высота элемента меньше и первый и второй элементы видны на странице, для второго элемента функция не запускается, и если я прокручиваю, она переходит к третьему элементу, и только когда я снова прокручиваю верхнюю часть, функция запускается для второго элемента тоже .. почему? :( - person coder; 04.08.2020
comment
а также, если я прокручиваю вниз и перезагружаю страницу, он не запускается для последнего элемента, пока я не прокручу вверх ... - person coder; 04.08.2020
comment
@coder Вот как вы указали, что ваша функция работает: entries[0].isIntersecting вы всегда тестируете только первый наблюдаемый элемент, а не каждый элемент в списке entries. Используйте цикл и проверьте каждый элемент в entries, и он работает. - person Andreas; 04.08.2020