繁体   English   中英

用于无限滚动的 Intersection Observer API

[英]Intersection Observer API for infinite scrolling

我正在做一个抽搐的网络应用程序。 我尝试使用 Intersection 观察者 API 来实现无限滚动并且它有效。 但是,我注意到当无限滚动工作时我的导航栏完全消失了。 我猜这个问题是由“DOMContentLoaded”引起的,但不确定。 谢谢你。

这是我的代码笔链接: Twitch

 const clientID = '5npghe3kytuifte3z9kvwnto50mqch'; const req = new XMLHttpRequest(); function showError() { alert('Error'); } function getResp(url, callback) { req.open('GET', url, true); req.setRequestHeader('Client-ID', clientID); req.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json'); req.send(); req.onload = function () { if (req.status >= 200 && req.status < 400) { let data try { data = JSON.parse(req.response) } catch (err) { showError(); return; } callback(data) } else { showError(); } } } const navList = document.querySelector('.nav__list') const streamBox = document.querySelector('.stream_box') const streamItems = document.querySelector('.streamItems') const langFilter = document.querySelector('.langFilter') const langArr = ['ALL', 'EN', 'ZH', 'ES', 'FR', 'DE', 'RU', 'KO', 'JA', 'PT', 'AR']; const urlRoot = 'https://api.twitch.tv/kraken/' const topGameurl = `${urlRoot}games/top?limit=5` const streamApi = `${urlRoot}streams/` let offset = 0 document.addEventListener('DOMContentLoaded', ()=> { const target = document.querySelector('.stream-end') let options = { root: null, rootMargin: '30px', // looking entire viewport threshold: 0.5, // if 50% of footer } const observer = new IntersectionObserver(handleIntersection, options) observer.observe(target) }) function handleIntersection(entries) { if (entries[0].isIntersecting) { let gameTitle = document.querySelector('.gameTitle') let gameURLname = encodeURIComponent(gameTitle.innerHTML) const loadmorestreamUrl = createURL(streamApi, gameURLname, offset) offset += 100 getData(loadmorestreamUrl) } } function createURL(url, game, offset) { const streamUrl = `${url}?game=${game}&limit=20&offset=${offset}` return streamUrl } getResp(topGameurl, (data) => { const topGames = [...data.top] const result = topGames.reduce((result, item) => { result += `<li>${item.game.name}</li>` return result }, '') navList.innerHTML = result const gameName = encodeURIComponent(data.top[0].game.name) const streamUrl = createURL(streamApi, gameName, offset) getData(streamUrl) }) navList.addEventListener('click', e => { streamItems.innerHTML = '' let gameTitle = document.querySelector('.gameTitle') const gameName = e.target.innerHTML gameTitle.innerHTML = gameName const gameNameURL = encodeURIComponent(gameName) const streamUrl = createURL(streamApi, gameNameURL, offset) getData(streamUrl) }) function getData(url) { getResp(url, (data) => { const dataArrs = [...data.streams] dataArrs.map(dataArr => { let streamItem = document.createElement('div') streamItem.classList.add('stream') streamItem.innerHTML = ` <p class="viewers">Viewers: ${dataArr.viewers}</p> <img src="${dataArr.preview.large}" alt="" class="preview"> <div class="streamer"> <img src="${dataArr.channel.logo}" alt="" class="logo"> <p class="name">${dataArr.channel.name}</p> <p class="lang">${dataArr.channel.broadcaster_language.toUpperCase()}</p> </div> ` streamItems.appendChild(streamItem) }) }) }
 html, body { font-size: 16px; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background:black; background-attachment: fixed; } .container { width: 90%; margin: 0 auto; display: flex; flex-direction: column; padding: 2rem; overflow-x: hidden; } #header { display: flex; justify-content: space-between; align-items: center; color: #fff; margin-bottom: 1.2rem; } .navbar { position: relative; transform: translateX(0%); } .title { margin-right: 1rem; font-size: 2rem; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-weight: 700; color: #741cf7; } .nav__list { display: flex; } .nav__list li { padding: .8rem .6rem; cursor: pointer; font-size: 1rem; font-weight: 700; } .nav__list li:hover { border-radius: .5rem; background: #a87ceb; transition: background .3s ease; } .nav__list li + li { margin-left: 1rem; } #stream_box { display: flex; flex-direction: column; border-radius: 8px; align-items: center; padding: 1.5rem; color: #fff; position: relative; } .game__title { font-size: 2rem; margin-bottom: 1rem; font-weight: 600; color:#741cf7; } .top__twenty { font-size: 1.4rem; margin-bottom: 1.5rem; } .streamItems { display: flex; flex-flow: row wrap; width: 100%; justify-content: center; } .lang__options { position: absolute; top: 2rem; right: 7rem; } .lang__title { font-size: 1.2rem; color: #fff; } #language { outline: none; width: 3rem; background: transparent; color: #741cf7; border: none; font-size: 1rem; } .stream { width: 30%; margin: 1.5rem; background-color: rgba(255, 255, 255, .15); backdrop-filter: blur(5px); cursor: pointer; } .preview { width: 100%; vertical-align: middle; } .viewers { display: none; } .stream:hover > .viewers { display: block; position: absolute; z-index: -1; animation-name: move; animation-duration: .4s; animation-timing-function: ease; animation-fill-mode: forwards; } @keyframes move { from { top: 0px; } to { top: -20px; } } .streamer { display: flex; align-items: center; padding: .5rem; position: relative; color: #fff; } .logo { width: 15%; border-radius: 50%; margin-right: .8rem; } .lang { position: absolute; right: .5rem; bottom: .5rem; } .hidden { display: none; } .check { display: none; } .rwdSwitch { display: none; } .gameTitle { color: #fff; } @media screen and (max-width: 1024px) { .lang__options { position: absolute; top: 7rem; right: 50%; transform: translateX(50%); } .streamItems { flex-flow: row wrap; width: 100%; justify-content: center; margin-top: 1.2rem; } .stream { width: 100%; } .nav__list li { text-align: center; font-size: 1rem; } } @media screen and (max-width: 576px) { body { overflow-x: hidden; } .navbar { position: absolute; top: 20%; right: 50%; transform: translateX(200%); transition: transform .3s ease-in-out; background-color: rgba(255, 255, 255, .15); backdrop-filter: blur(5px); z-index: 999; visibility: hidden; } .top__twenty { font-size: .8rem; } .nav__list { flex-direction: column; align-items: flex-end; } .rwdSwitch { display: block; cursor: pointer; position: absolute; right:1.5rem; top: 2.5rem; z-index: 999; } .check:checked ~ .navbar { visibility: visible; transform: translateX(100%); transition: transform .3s ease-in-out; } }
 <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="reset.css"> <link rel="stylesheet" href="style.css"> <title>Twitch</title> </head> <body> <div class="container"> <header id="header"> <label for="check__status" class="rwdSwitch"><i class="fas fa-bars"></i></label> <input type="checkbox" class="check" id="check__status"> <h1 class="title">Twitch Top Games</h1> <nav class="navbar"> <ul class="nav__list"></ul> </nav> </header> <div class="selections"> <label for="language" class="lang__title">Filter by Language: </label> <select name="lang" id="language" class="langFilter"></select> </div> <main class="stream_box"> <p class="gameTitle"></p> <div class="streamItems"></div> </main> <div class="stream-end"></div> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/js/all.min.js"></script> <script src="api.js"></script> <script src="app.js"></script> </body> </html>

首先请不要使用XMLHttpRequest它很旧,很难使用和阅读。 使用fetch代替。

您的问题是由您创建一个XMLHttpRequest的事实引起的。 所以在第一个请求完成之前,第二个请求开始并取消第一个请求。 只需移动const req = new XMLHttpRequest(); getResp

但我只是将getResp更改为:

function getResp(url, callback) {
  fetch(url, {
    headers: {
      'Client-ID': clientID,
      'Accept': 'application/vnd.twitchtv.v5+json'
    }
  })
  .then(response => response.json())
  .then(callback)
  .catch(showError)
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM