成品
Infinite Scroll Blog
介紹
利用 JSON Server 產生假文章做無限滾動的練習。
功能
- 當捲動到頁尾時,會自動讀取( load ) 更多的文章,讀取時有動畫顯示
- 文章搜尋功能,可以篩選符合的文章內容
獲取文章資料
使用 fetch()
來取得遠端的文章資料,這次改用 async/await
來進行改寫,在結構上較易於閱讀。因為檔案為 json 格式,所以在取得檔案後透過 json()
處理檔案。
而我們一開始預設顯示的文章數為一頁五篇文章,以方便我們可以滾動頁面。
1 2 3 4 5 6 7 8 9 10 11 12
| let limit = 5; let page = 1;
async function getPosts() { const res = await fetch( `https://jsonplaceholder.typicode.com/posts?_limit=${limit}&_page=${page}` );
const data = await res.json();
return data; }
|
設置初始文章
我們用一個函式來處理剛拿到的遠端資料,讓其依照順序一一呈現在網頁上。
- 每一篇文章都用一個
<div>
包起來
- 增加 class
post
以套用 CSS 設定
- 依照順序把文章的標題跟內容放進去
網頁讀取時先呼叫一次,這時候會顯示我們預設的五篇文章數。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| async function showPosts() { const posts = await getPosts();
posts.forEach(post => { const postEl = $('<div></div>').appendTo(postsContainer); postEl.addClass('post'); postEl.html(` <div class="number">${post.id}</div> <div class="post-info"> <h2 class="post-title">${post.title}</h2> <p class="post-body">${post.body}</p> </div> `); }); }
showPosts();
|
讀取動畫
當滑到頁尾時,我們增加一個讀取的顯示,用 JS 切換 class 中 opacity
的屬性,來操控它的顯示。
HTML
1 2 3 4 5
| <div class="loader"> <div class="circle"></div> <div class="circle"></div> <div class="circle"></div> </div>
|
CSS
1 2 3
| .loader.show { opacity: 1;
|
再來我們增加點動畫效果,讓它做到上下的位移,並且是依序跳動的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| .circle { animation: bounce 0.5s ease-in infinite; }
.circle:nth-of-type(2) { animation-delay: 0.1s; }
.circle:nth-of-type(3) { animation-delay: 0.2s; }
@keyframes bounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
|
顯示文章
對瀏覽器中的視窗監控 scroll 事件,當瀏覽器滾動到頁尾時觸發函式,當動畫顯示 1 秒後會移除,接著間隔 0.3 秒後從遠端讀取文章資料並顯示在頁面上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function showLoading() { loading.addClass('show');
setTimeout(() => { loading.removeClass('show');
setTimeout(() => { page++; showPosts(); }, 300); }, 1000); }
$(window).scroll(function() { const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
if (scrollTop + clientHeight >= scrollHeight - 5) { showLoading(); } });
|
這邊說明一下 scrollTop
、clientHeight
、scrollHeight
之間的關係
scrollTop
: 是「內容」被捲動的距離,也就是內容頂端和捲軸頂端的相對距離,代表在有滾動條時,滾動條向下滾動的距離也就是元素頂部被遮住部分的高度。
clientHeight
: 包括 padding 但不包括 border、水平滾動條、margin 的元素的高度。
scrollHeight
: 和 clientHeight
屬性類似,但包含滾動 ( 隱藏 ) 的部分。
了解之後我們知道完整的內容高度 (scrollHeight
) = 內容頂端和捲軸頂端的距離 (scrollTop
) + 內容本身高度(clientHeight
),所以當滑到頁尾時也就是 (scrollTop + clientHeight >= scrollHeight - 5
) 會觸發產生新的文章,而之所以會 scrollHeight -5
是希望在接近底時就能夠觸發。
搜尋文章
透過監聽搜尋欄位的 input
觸發搜尋的功能,indexOf()
方法會回傳某個指定的字符串值在字符串中首次出現的位置,如果沒有找到則回傳 -1
,對此我們將符合的文章顯示,不符合的則隱藏,toUpperCase()
則是方便我們搜尋,可以忽略大小寫的輸入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function filterPosts(e) { const term = e.target.value.toUpperCase(); const posts = document.querySelectorAll('.post');
posts.forEach(post => { const title = post.querySelector('.post-title').innerText.toUpperCase(); const body = post.querySelector('.post-body').innerText.toUpperCase();
if (title.indexOf(term) > -1 || body.indexOf(term) > -1) { post.style.display = 'flex'; } else { post.style.display = 'none'; } }); }
document.getElementById('filter').addEventListener('input', filterPosts);
|
參考資料