๐ค๋ฌดํ ์คํฌ๋กค(Infinite scroll)์ด๋?
๋ฌดํ ์คํฌ๋กค์ ์ฌ์ฉ์๊ฐ ํ์ด์ง ํ๋จ์ ๋๋ฌํ์ ๋, ์ฝํ ์ธ ๊ฐ ๊ณ์ ๋ก๋๋๋ ์ฌ์ฉ์ ๊ฒฝํ(UX) ๋ฐฉ์์ ๋๋ค. ํ ํ์ด์ง ์๋๋ก ์คํฌ๋กค ํ๋ฉด ๋์์ด ์๋ก์ด ํ๋ฉด์ ๋ณด์ฌ์ฃผ๊ฒ ๋๊ณ ์ด๋ก ์ธํด ๋ง์ ์์ ์ฝํ ์ธ ๋ฅผ ์คํฌ๋กค ํด์ ๋ณผ ์ ์์ต๋๋ค.
๊ฒ์ํ์ ๋ง์ ์์ ๊ธ์ ํธ๋ฆฌํ๊ฒ ๋ณด๊ธฐ ์ํด ๋ฌดํ ์คํฌ๋กค ๋ฐฉ๋ฒ์ผ๋ก ํ์ด์ง ๊ธฐ๋ฅ์ ๊ตฌํํด ๋ดค์ต๋๋ค.
[๐๋ฌดํ ์คํฌ๋กค์ ์ฅ์ ]
- ์ฌ์ฉ์ ์ฐธ์ฌ ๋ฐ ์ฝํ ์ธ ํ์์ด ์ฝ์ต๋๋ค.
- ๋ฌดํ ์คํฌ๋กค์ด ํด๋ฆญํ๋ ๊ฒ๋ณด๋ค ๋ ๋์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํฉ๋๋ค.
(๋ค์ ์ฝํ
์ธ ๋ฅผ ๋ณด๊ธฐ ์ํ ์ถ๊ฐ ํด๋ฆญ์ด ํ์์๊ณ ํ์ด์ง ๋ก๋ ์๊ฐ์ด ์งง์ต๋๋ค.)
- ํฐ์น์คํฌ๋ฆฐ(๋ชจ๋ฐ์ผ)์ผ๋ ๋ ์ ์ฉํ๊ฒ ์ ์ฉ๋ฉ๋๋ค.
(ํ๋ฉด์ด ์์์๋ก ์คํฌ๋กค์ ๊ธธ์ด์ง๊ธฐ์ ๋ชจ๋ฐ์ผ ํ๊ฒฝ์์ ์ฝํ
์ธ ๋ฅผ ๋ณด์ฌ์ฃผ๊ธฐ ์ง๊ด์ ์ด๊ณ ์ฌ์ฉํ๊ธฐ ์ฌ์ด ํ์)
[๐๋ฌดํ ์คํฌ๋กค์ ๋จ์ ]
- ํ์ด์ง ์ฑ๋ฅ์ด ๋๋ ค์ง๋๋ค.
- ํน์ ํญ๋ชฉ ๊ฒ์ ๋ฐ ์๋ ์์น๋ก ๋๋์์ค๊ธฐ ํ๋ญ๋๋ค.
- ์คํฌ๋กค ๋ง๋๊ฐ ์ค์ ๋ฐ์ดํฐ์์ ๋ฐ์ํ์ง ๋ชปํฉ๋๋ค.
- ํธํฐ๋ฅผ ์ฐพ๊ธฐ ์ด๋ ค์์ง๋๋ค.
[๐ํ์ด์ง ๋ค์ด์ VS ๋ฌดํ ์คํฌ๋กค VS ๋๋ณด๊ธฐ ๋ฒํผ]
๋ค์ํ ํ์ด์ง ๊ธฐ๋ฅ๋ค ์ค ์ ๊ฐ ๋ฌดํ ์คํฌ๋กค ๊ธฐ๋ฅ์ ํํ ์ด์ ๋
1. ์ฌ์ฉ์์ ํด๋ฆญ์ ์ต์ํ ํ๋ฉด์ ํ ๋ฒ์ ๋ง์ ์์ ๋ฐ์ดํฐ๋ฅผ ๋ณด์ฌ์ฃผ๊ณ ์ถ๋ค
2. ํ์ด์ง ๋ค์ด์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ ๋ ๋ณด๋ค ์ฌ์ฉ์๋ค์ด ๋ ์ฝ๊ฒ ๋ค์ํ ์ฝํ ์ธ ๋ฅผ ๋ณผ ์ ์๋ค
์ด๋ฌํ ์ด์ ๋ก ๋ฌดํ ์คํฌ๋กค ๊ธฐ๋ฅ์ ํํ๊ฒ ๋์์ต๋๋ค.
โ๋ฌดํ ์คํฌ๋กค ๊ตฌํํ๊ธฐ
1 | ์คํฌ๋กค์ด ๋ฐ๋ฅ์ ๋ฟ๊ฒ ๋๋ฉด 20๊ฐ์ ์์ดํ ์ ๋ณผ๋ฌ์จ๋ค. |
2 | 20๊ฐ์ ์์ดํ ์ ๋ถ๋ฌ์ค๋ ์๊ฐ ๋์ ์ค์ผ๋ ํค UI์ ๋ก๋ฉ UI๋ฅผ ๋์ด๋ค. |
3 | ํด๋น ์์ดํ ์ ์์ธ๋ณด๊ธฐ ์ฐฝ์์ ๋ค๋ก ๊ฐ๊ธฐ๋ฅผ ๋๋ฅด๋ฉด ๊ธฐ์กด์ ์คํฌ๋กค์ด ์ ์ง๋๋ค. |
4 | ์์ดํ ์ด ๋ค ๋ถ๋ฌ์์ง๋ฉด ๋ฌดํ ์คํฌ๋กค์ ๋ฉ์ถ๊ฒ ๋๋ค. |
์ ๊ฐ ์๊ฐํ ๋ฌดํ ์คํฌ๋กค์ ๊ตฌํํ์ ๋ ๊ฐ์ ธ์ผํ ๊ธฐ๋ฅ๋ค์ ๋๋ค. ํ๋์ฉ ์ฐจ๊ทผ์ฐจ๊ทผ ๊ตฌํํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
[1. IntersectionObserver์ ์ด์ฉํ ๋ฌดํ์คํฌ๋กค ๊ตฌํ]
JS๋ก ๋ฌดํ์คํฌ๋กค์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ๋ค์ํฉ๋๋ค. ๊ทธ ์ค ์ ๋ IntersectionObserver API
๋ฅผ ์ด์ฉํ์ต๋๋ค.
๐คIntersectionObserver๋?
IntersectionObserver
์ธํฐํ์ด์ค๋ ๋์ ์์์ ๊ทธ ์์ ์์ ํน์ ์ต์์ ๋ํ๋จผํธ์ธ viewport
์์ ๊ต์ฐจ ์์ญ์ ๋ํ ๋ณํ๋ฅผ ๋น๋๊ธฐ์ ์ผ๋ก ๊ฐ์งํ ์ ์๋๋ก ๋์์ค๋๋ค.
์ฆ, arget Element
๊ฐ ํ๋ฉด์ ๋
ธ์ถ๋์๋์ง ์ฌ๋ถ๋ฅผ ๊ฐ๋จํ๊ฒ ๊ตฌ๋
ํ ์ ์๋ API
์
๋๋ค.
var intersectionObserver = new IntersectionObserver(function(entries) {
// If intersectionRatio is 0, the target is out of view
// and we do not need to do anything.
if (entries[0].intersectionRatio <= 0) return;
loadItems(10);
console.log('Loaded new items');
});
// start observing
intersectionObserver.observe(document.querySelector('.scrollerFooter'));
IntersectionObserver
๋ Callback
ํจ์๋ฅผ ํตํด ๋๊ฐ์ ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ์ต๋๋ค.
new IntersectionObserver(callback[, options]);
entries
- →๋ ๋ณด์ด๊ฑฐ๋ ๋ ๋ณด์ด๊ฒ ๋๋ฉด์ ํต๊ณผํ ์ญ์น๋ฅผ ๋ํ๋ด๋,
IntersectionObserverEntry (en-US)
๊ฐ์ฒด์ ๋ฐฐ์ด. observer
- → ์์ ์ ํธ์ถํ
IntersectionObserver
์ด ๊ธฐ๋ฅ์ ์ด์ฉํด ํ๋ฉด ๋งจ ์๋ div
์์๋ฅผ ๋ฃ์ด ์ด div
์์๋ฅผ IntersectionObserver
๊ฐ ๊ฐ์ํ๋๋ก ๊ตฌํํ์ต๋๋ค.
<div class="list"></div>
<p id="sentinel"></p>
const io = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (!entry.isIntersecting) return;
//entry๊ฐ interscting ์ค์ด ์๋๋ผ๋ฉด ํจ์๋ฅผ ์คํํ์ง ์์ต๋๋ค.
if (page._scrollchk) return;
//ํ์ฌ page๊ฐ ๋ถ๋ฌ์ค๋ ์ค์์ ๋ํ๋ด๋ flag๋ฅผ ํตํด ๋ถ๋ฌ์ค๋ ์ค์ด๋ฉด ํจ์๋ฅผ ์คํํ์ง ์์ต๋๋ค.
observer.observe(document.getElementById('sentinel'));
//observer๋ฅผ ๋ฑ๋กํฉ๋๋ค.
page._page += 1;
//๋ถ๋ฌ์ฌ ํ์ด์ง๋ฅผ ์ถ๊ฐํฉ๋๋ค.
page.list.search();
//ํ์ด์ง๋ฅผ ๋ถ๋ฌ์ค๋ ํจ์๋ฅผ ํธ์ถํฉ๋๋ค.
});
});
io.observe(document.getElementById('sentinel'));
[2. ์์ดํ ์ด ๋ก๋ฉ๋๊ธฐ ์ UI ๊ตฌํ]
IntersectionObserver
๋ฅผ ํตํด ์คํ๋ search
ํจ์์์ ajax
๋ฅผ ํตํด ์์ดํ
์ ๊ฐ์ ธ์ต๋๋ค.
์ด๋, beforeSend
์ complete
๋ฅผ ํตํด์ Skeleton UI์ Loading animation ์ฝ์
, ์ญ์ ๋ฅผ ๊ตฌํํ์ต๋๋ค.
$.ajax({
url: url,
data: param,
method: "GET",
dataType: "json",
success: function (result) {
console.log(result);
},
error: function (err) {
console.log(err);
},
beforeSend: function () {
_scrollchk = true;
//๋ฐ์ดํฐ๊ฐ ๋ก๋ ์ค์์ ๋ํ๋ด๋ flag์
๋๋ค.
document.getElementById('list').appendChild(skeleton.show());
//skeleton์ ๊ทธ๋ฆฌ๋ ํจ์๋ฅผ ์ด์ฉํด DOM์ ์ถ๊ฐํด์ค๋๋ค.
$(".loading").show();
//loading animation์ ๊ฐ์ง ์์๋ฅผ ๋ณด์ฌ์ค๋๋ค.
},
complete: function () {
_scrollchk = false;
//๋ฐ์ดํฐ๊ฐ ๋ก๋ ์ค์์ ๋ํ๋ด๋ flag์
๋๋ค.
$(".loading").hide();
skeleton.hide();
//loading animation ์์์ skeleton์ ์ง์ฐ๋ ํจ์๋ฅผ ์ด์ฉํด DOM์์ ์ง์์ค๋๋ค.
}
});
[3. ๋ฌดํ ์คํฌ๋กค ๋ฉ์ถ๊ธฐ ๊ตฌํ]
๋ชจ๋ ์์ดํ
์ด ๋ค ๋ถ๋ฌ์ค๊ฑฐ๋ ๊ฒ์ ์ 20๊ฐ์ ์์ดํ
๋ณด๋ค ์ ๊ฒ ๊ฒ์๋๋ ๊ฒฝ์ฐ ๋ ์ด์ IntersectionObserver
์ ๊ฐ์๋ฅผ ๋ฐ์ง ์๋๋ก ๋ง๋ค์ด์ผ ํฉ๋๋ค.
IntersectionObserver.unobserve(target);
IntersectionObserver API
์๋ ์ง์ ๋ ๋์ ์์ ๊ด์ฐฐ์ ์ค์งํ๋ unobserve
๋ฉ์๋๊ฐ ์กด์ฌํ๋๋ฐ ์ด๋ฅผ ์ด์ฉํด ๊ด์ฐฐ์ ์ค์งํ ์ ์์ต๋๋ค.
var observer = new IntersectionObserver(callback);
observer.observe(document.getElementById("elementToObserve"));
/* ... */
observer.unobserve(document.getElementById("elementToObserve"));
์ด๋ ๊ฒ ๊ด์ฐฐ์ ์ค์งํ ์๋ ์์ง๋ง, ์ ๋ ๊ฐ๋จํ๊ฒ ์ง๊ธ ๊ด์ฐฐ์ค์ธ ์์๋ฅผ ์ด์ฉํด ๊ด์ฐฐ ๋์์ DOM
์์ ์จ๊ธฐ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํํ์ต๋๋ค.
if (_total === 0) {
$('#sentinel').hide();
//๊ฒ์๋ ์์ดํ
์ด ์์ ๊ฒฝ์ฐ ๊ด์ฐฐ์ค์ธ ์์๋ฅผ ์จ๊ธด๋ค.
}
else {
if (_total <= _page*20){
$('#sentinel').hide();
//๊ฒ์๋ ์์ดํ
์ด 20๊ฐ ์ดํ์ผ ๊ฒฝ์ฐ ๊ด์ฐฐ์ค์ธ ์์๋ฅผ ์จ๊ธด๋ค.
}
else {
$('#sentinel').show();
//๊ด์ฐฐ์ค์ธ ์์๋ฅผ ๋ณด์ฌ์ค๋ค.
}
}
[4. ๋ค๋ก ๊ฐ๊ธฐ ์ ์ด์ ์คํฌ๋กค ์ ์ง ๊ตฌํ]
์ฌ์ฉ์๊ฐ ์์ดํ ์ ์์ธ๋ณด๊ธฐ ํ์ด์ง๋ก ์ด๋ ํ ํ ๋ค์ ๋ค๋ก๊ฐ๊ธฐ๋ฅผ ์ด์ฉํด ๋ฌดํ ์คํฌ๋กค ํ์ด์ง๋ก ๋์์์ ๋, ํ์ด์ง๊ฐ ๋ค์ ๋งจ ์ฒ์์ฒ๋ผ ๋ก๋๋์ด ์๋ค๋ฉด ๋ค์ ๋ณด๊ณ ์๋ ์์ดํ ๊น์ง ์คํฌ๋กค์ ํด์ผ ํ๋ ๋ถํธํจ์ด ๋ฐ์ํฉ๋๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด, ๊ธฐ์กด์ ๋ณด๊ณ ์๋ ํ์ด์ง๋ก ์คํฌ๋กค์ ์ฎ๊ธฐ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํ์ต๋๋ค.
๋ธ๋ผ์ฐ์ ๋ค๋ก๊ฐ๊ธฐ ์ด๋ฒคํธ ๊ฐ์ง๋ฅผ ์ด๋ฒคํธ ์ฒ๋ฆฌํด์ค๋๋ค.
window.addEventListener('pageshow', function (event) {
if (event.persisted || window.performance && window.performance.navigation.type == 2) {
//
}
});
์์ธ๋ณด๊ธฐ ํ์ด์ง๋ก ๋์ด๊ฐ๊ธฐ ์ ํ์ด์ง๋ฅผ sessionStorage
์ ์ ์ฅํ ํ ๋ค๋ก๊ฐ๊ธฐ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด sessionStorage
์์ ๊ฐ์ ๊ฐ์ ธ์ ๋๊ฒจ์ค๋๋ค.
if (sessionStorage.getItem("page")) {
var pageNum = Number.parseInt(sessionStorage.getItem("page"));
_page = pageNum ;
list.search();
}
์ต์ข ๊ฒฐ๊ณผโ
'FRONT > JavaScript' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[JS] Cropper.js ์ฌ์ฉ๊ธฐ (0) | 2022.02.05 |
---|---|
[KENDO JS] DataSource๋ฅผ gird, listview์ ์ฌ์ฌ์ฉํ๊ธฐ (0) | 2021.10.08 |
[JS] JavaScript ์ค์ฝํ (0) | 2021.07.01 |
[JS] vanilla js๋ก Pagination ๊ตฌํํ๊ธฐ (0) | 2021.07.01 |