學習到的知識點 CSS
position: absolute
position: fixed
:nth-of-type(2)
JS
Asynchronous 非同步
await
promise
jQuery.each()
scrollTop,clientHeight,scrollHeight
:contains() Selector
簡介 滾動到畫面底部時,會不停出現文章。
HTML HTML Code
結構
標題與搜尋框
1 2 3 4 5 6 7 8 9 <h1 > My Blog</h1 > <div class ="filter-container" > <input type ="text" id ="filter" class ="filter" placeholder ="Filter posts..." /> </div >
JS 動態產的區域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <div id ="posts-container" > <div class ="post" > <div class ="number" > 1</div > <div class ="post-info" > <h2 class ="post-title" > Post One</h2 > <p class ="post-body" > Lorem ipsum dolor sit, amet consectetur adipisicing elit. Tempore, repellat! Eveniet consequuntur quasi voluptas pariatur cupiditate fuga voluptatem doloremque dolor sed illo. Laudantium itaque voluptas fugiat unde placeat quam consectetur? </p > </div > </div > </div >
Loading 動畫
1 2 3 4 5 <div class ="loader" > <div class ="circle" > </div > <div class ="circle" > </div > <div class ="circle" > </div > </div >
CSS 每篇文章產生的樣式 數字的絕對定位需要記住,往左上偏移所以是(-15px,-15px),再使用 flex 定位在圓圈中間。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 .post { position : relative; background-color : #4992d3 ; box-shadow : 0 2px 4px rgba (0 , 0 , 0 , 0.3 ); border-radius : 3px ; padding : 20px ; margin : 40px 0 ; display : flex; width : 80vw ; max-width : 800px ; }.post .post-title { margin : 0 ; }.post .post-body { margin : 15px 0 0 ; line-height : 1.3 ; }.post .post-info { margin-left : 20px ; }.post .number { position : absolute; top : -15px ; left : -15px ; font-size : 15px ; width : 40px ; height : 40px ; border-radius : 50% ; background : #fff ; color : #296ca8 ; display : flex; align-items : center; justify-content : center; padding : 7px 10px ; }
Loading 動畫 一開始設定opacity: 0
不要出現,.show
用 Js 控制。
position: fixed
,是針對視窗做定位,和absolute
很像,運用在蓋板廣告較多。
:nth-of-type(2)
,選擇第二個元素,它與第三個元素秒數不同,形成動畫效果。
每一個圈圈都加上動畫,再依據時間delay
呈現 loading 效果ㄡ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 .loader { opacity : 0 ; display : flex; position : fixed; bottom : 50px ; transition : opacity 0.3s ease-in; }.loader .show { opacity : 1 ; }.circle { background-color : #fff ; width : 10px ; height : 10px ; border-radius : 50% ; margin : 5px ; 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 ); } }
JS JS Code
Jquery Code
宣告變數
原生 JS
1 2 3 4 5 6 7 const postsContainer = document .getElementById ("posts-container" );const loading = document .querySelector (".loader" );const filter = document .getElementById ("filter" );let limit = 3 ; let page = 1 ;
Jquery
1 2 3 4 5 6 $("#posts-container" ) $("#loader" ) $("#filter" )let limit = 3 ;let page = 1 ;
取得假文章 到 jsonplaceholder 獲取 json api 利用網址的方式取得,再利用網址分析。
https://jsonplaceholder.typicode.com/posts
?_limit=3
一次三篇
?_limit=3&_page=2
換到第二頁面,所以出現的會是 4,5,6
解說 getPosts()
showPosts()
async 非同步
在 ES7 裡頭 async 的本質是 promise
的語法,只要 function
標記為 async
,就表示裡頭可以撰寫 await
的同步語法,而 await
顧名思義就是「等待」。
因為 fetch 最後回傳的是promise
,透過 async 和 await 操作是最適合的。
取得 JSON 格式的連結,透過fetch
的json()
方法處理檔案,就可以顯示出我們要的內容。
posts 裡面存放了我們取得的使我們要的資料,而 post 是取出來的一筆筆資料。
posts
post
可以利用開發者工具看出來他們資料的差異。
原生 JS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 async function getPosts ( ) { const res = await fetch ( `https://jsonplaceholder.typicode.com/posts?_limit=${limit} &_page=${page} ` ); const data = await res.json (); return data; }async function showPosts ( ) { const posts = await getPosts (); posts.forEach ((post ) => { const postEl = document .createElement ("div" ); postEl.classList .add ("post" ); postEl.innerHTML = ` <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> ` ; postsContainer.appendChild (postEl); }); }showPosts ();
Jquery
使用$.ajax
,使用get
方法,再利用$.each
讀取每一個值。
async function getPosts() {}
轉成 $.ajax({})
posts.forEach((post) => {}
轉成 $.each(data, function (index, post) {}
jQuery.each()
.each()舉例來說 .each()是用來遍歷選擇的元素們 ,可以用在陣列與物件。陣列裡,它會回傳index
和array value
。
陣列(這邊使用到的方法) 1 2 3 4 5 6 $.each ([ 52 , 97 ], function ( index, value ) { alert ( index + ": " + value ); });
物件 1 2 3 4 5 6 7 8 9 10 var obj = { "flammable" : "inflammable" , "duh" : "no duh" }; $.each ( obj, function ( key, value ) { alert ( key + ": " + value ); });
這部分的 Jquery
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 let limit = 5 ;let page = 1 ;function showPosts ( ) { $.ajax ({ url : `https://jsonplaceholder.typicode.com/posts?_limit=${limit} &_page=${page} ` , method : "get" , dataType : "json" , success : function (data ) { console .log (data); $.each (data, function (index, post ) { const postEl = $("<div>" ).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> ` ); $("#posts-container" ).append (postEl); }); }, }); }
畫面到底時,增加文章 解說 showLoading()
addEventListener
這邊利用了setTimeout()
非同步方法,Loading 動畫先跑 1 秒,跑完後花 0.3 秒跑出文章。
window.addEventListener
,這邊監聽的是整個網頁的滾動,所以要使用到 window 的 scroll。
關於如何計算內容底端距離捲軸底端的距離,在另外一篇筆記解說 。
原生 JS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 function showLoading ( ) { loading.classList .add ("show" ); setTimeout (() => { loading.classList .remove ("show" ); setTimeout (() => { page++; showPosts (); }, 300 ); }, 1000 ); }window .addEventListener ("scroll" , () => { const { scrollTop, scrollHeight, clientHeight } = document .documentElement ; if (scrollTop + clientHeight >= scrollHeight - 5 ) { showLoading (); } });
Jquery
loading.classList.add("show")
轉成$(".loader").addClass("show")
loading.classList.remove("show")
轉成$(".loader").removeClass("show")
window.addEventListener("scroll", () => {}
轉成$(window).scroll(function () {}
scrollTop
轉成$(document).scrollTop()
clientHeight
轉成$(window).height()
scrollHeight
轉成$(document).height()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function showLoading ( ) { $(".loader" ).addClass ("show" ); setTimeout (() => { $(".loader" ).removeClass ("show" ); setTimeout (() => { page++; showPosts (); }, 300 ); }, 1000 ); } $(window ).scroll (function ( ) { if ($(document ).scrollTop () + $(window ).height () > $(document ).height () - 5 ) { showLoading (); } });
內文搜尋 解說 filterPosts()
使用者輸入的內容轉換成大寫或全部小寫判斷都可以,然後取的每一個 post,再來驗證 title 跟 body 有沒有符合的,如果有 indexOf 就會從 0 開始遞增,然後執行flex
,所以判斷才會是>-1。
addEventListener
裡的input
,只要一輸入就會執行filterPosts
,不需要等到按下 Enter。
原生 JS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 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" ; } }); } filter.addEventListener ("input" , filterPosts);
Jquery
const term = e.target.value.toUpperCase()
轉成 const term = $("input").val().toLowerCase()
$(
.post:contains(‘${term}’)).css("display", "flex")
filter.addEventListener("input", filterPosts)
轉成 $("input").on("input", function () { filterPosts() });
$(.post:contains(’${term}’))
,這行的 Jquery 轉換的寫法是參考別人的寫法,因為原生的寫法太複雜,研究了許久還是無法正確轉換,後來發現 Jquery 有:contains
這個功能,簡化了許多原生 JS 步驟,值得紀錄。
:contains() Selector
1 2 3 4 5 6 7 8 9 10 function filterPosts ( ) { const term = $("input" ).val ().toLowerCase (); $(".post" ).css ("display" , "none" ); $(`.post:contains('${term} ')` ).css ("display" , "flex" ); } $("input" ).on ("input" , function ( ) { filterPosts (); });
參考文章 JS async function
JavaScript 中的同步與非同步(上):先成為 callback 大師吧!
簡單理解 JavaScript Async 和 Await