thymeleaf使用th:each屬性可以對數(shù)組,集合進(jìn)行循環(huán),此屬性用在容器元素上,循環(huán)生成子元素。
語法
th:each="循環(huán)出的元素 , 循環(huán)狀態(tài) : 集合或數(shù)組"
示例
在TestServlet中定義一個(gè)數(shù)組
String [] arr={"HTML","CSS","JavaScript"};
request.setAttribute("arr",arr);
在index.html中循環(huán)顯示數(shù)組中的元素
<div th:text="'數(shù)組元素?cái)?shù)量:' + ${arr.length}"> </div><!--獲取數(shù)組元素的數(shù)量-->
<ul th:each="s : ${arr}">
<li th:text="${s}"></li>
</ul>
運(yùn)行test.do,頁面顯示效果如下
在th:each中循環(huán)狀態(tài)不是必須的,它是一個(gè)對象,具有以下屬性
屬性名 | 說明 |
index | 整型屬性,當(dāng)前迭代索引,從0開始 |
count | 整型屬性,當(dāng)前的迭代計(jì)數(shù),從1開始 |
size | 整型屬性,迭代變量中元素的總量 |
current | 對象屬性,每次迭代的 iter 變量,即當(dāng)前遍歷到的元素 |
even/odd | 布爾屬性,當(dāng)前的迭代是偶數(shù)還是奇數(shù) |
first | 布爾屬性,當(dāng)前的迭代是否是第?個(gè)迭代 |
last | 布爾屬性,當(dāng)前的迭代是否是最后?個(gè)迭代。 |
修改上一個(gè)示例,顯示每次循環(huán)的各狀態(tài)的值
<table border="1">
<tr>
<th>當(dāng)前迭代索引</th>
<th>當(dāng)前迭代計(jì)數(shù)</th>
<th>元素的總量</th>
<th>當(dāng)前遍歷到的元素</th>
<th>當(dāng)前遍歷的偶數(shù)</th>
<th>是否是第一條</th>
<th>是否是最后一條</th>
</tr>
<tbody th:each="s,status : ${arr}">
<tr><td th:text="${status.index}"></td>
<td th:text="${status.count}"></td>
<td th:text="${status.size}"></td>
<td th:text="${status.current}"></td>
<td th:text="${status.even}"></td>
<td th:text="${status.first}"></td>
<td th:text="${status.last}"></td>
</tr>
</tbody>
</table>
運(yùn)行test.do,頁面顯示效果如下
示例
在TestServelt中添加一個(gè)List集合
List list=new ArrayList<>();
list.add("HTML");
list.add("CSS");
list.add("JavaScript");
request.setAttribute("list", list);
在index.html中循環(huán)顯示列表中的數(shù)據(jù)
<div th:text="'list中元素?cái)?shù)量:' + ${list.size}"> </div>
<ul th:each="s : ${list}">
<li th:text="${s}"></li>
</ul>
運(yùn)行test.do,頁面顯示效果如下
1) 直接訪問
map集合可以通過key獲取值,也可以獲取集合中元素的數(shù)據(jù)
示例
在TestServelt中添加map集合
Map<String,String> map=new HashMap<>();
map.put("HTML", "超文本標(biāo)記語言");
map.put("CSS", "層疊樣式表");
request.setAttribute("map", map);
在頁面中輸出map的信息
<ul>
<li >集合:[[${map}]]</li>
<li>指定key的值:[[${map.HTML}]]</li>
<li>集合中元素的數(shù)量:[[${map.size}]]</li>
</ul>
運(yùn)行test.do,頁面顯示效果如下
2)循環(huán)訪問
Map循環(huán)的每個(gè)元素的類型是Entry,可以通過此Entry對象的key屬性獲取鍵,value屬性獲取值
修改index.html,循環(huán)顯示map集合中的內(nèi)容
<ul th:each="entry : ${map}">
<li >
<strong th:text="${entry.key}"></strong>
:
<em th:text="${entry.value}"></em>
</li> </ul>
運(yùn)行test.do,頁面顯示效果如下
在使用th:if時(shí),如果是一當(dāng)條件成立需要加載一組標(biāo)簽,在循環(huán)時(shí),循環(huán)的元素外沒有容器時(shí),可以使用th:block標(biāo)簽做為外容器,th:block僅是一個(gè)屬性容器,允許開發(fā)人員指定他們想要的任何屬性
示例
<th:block th:each="s : ${list}">
<div th:text="${s}"></div></th:block>
文章來源于嗶站《六、循環(huán)表達(dá)式 - 嗶哩嗶哩》
更多學(xué)習(xí)視頻和專欄文章請到嗶站個(gè)人空間: 布道師學(xué)院的個(gè)人空間-布道師學(xué)院個(gè)人主頁-嗶哩嗶哩視頻
更多資源和項(xiàng)目下載請到:”開源吧(找實(shí)戰(zhàn)項(xiàng)目和畢設(shè)項(xiàng)目的好網(wǎng)站)“ :開源吧
javascript 是一門單線程的語言,在同一個(gè)時(shí)間只能做完成一件任務(wù),如果有多個(gè)任務(wù),就必須排隊(duì),前面一個(gè)任務(wù)完成,再去執(zhí)行后面的任務(wù)。作為瀏覽器端的腳本語言,javascript 的主要功能是用來和用戶交互以及操作 dom。假設(shè) javascript 不是單線程語言,在一個(gè)線程里我們給某個(gè) dom 節(jié)點(diǎn)增加內(nèi)容的時(shí)候,另一個(gè)線程同時(shí)正在刪除這個(gè) dom 節(jié)點(diǎn)的內(nèi)容,則會造成混亂。
由于 js 單線程的設(shè)計(jì),假設(shè) js 程序的執(zhí)行都是同步。如果執(zhí)行一些耗時(shí)較長的程序,例如 ajax 請求,在請求開始至請求響應(yīng)的這段時(shí)間內(nèi),當(dāng)前的工作線程一直是空閑狀態(tài), ajax 請求后面的 js 代碼只能等待請求結(jié)束后執(zhí)行,因此會導(dǎo)致 js 阻塞的問題。
javascript 單線程指的是瀏覽器中負(fù)責(zé)解釋和執(zhí)行 javascript 代碼的只有一個(gè)線程,即為 js 引擎線程,但是瀏覽器的渲染進(jìn)程是提供多個(gè)線程的,如下:
為解決上述類似上述 js 阻塞的問題,js 引入了同步和異步的概念。
“同步”就是后一個(gè)任務(wù)等待前一個(gè)任務(wù)結(jié)束后再去執(zhí)行。
“異步”與同步不同,每一個(gè)異步任務(wù)都有一個(gè)或多個(gè)回調(diào)函數(shù)。webapi 會在其相應(yīng)的時(shí)機(jī)里將回調(diào)函數(shù)添加進(jìn)入消息隊(duì)列中,不直接執(zhí)行,然后再去執(zhí)行后面的任務(wù)。直至當(dāng)前同步任務(wù)執(zhí)行完畢后,再把消息隊(duì)列中的消息添加進(jìn)入執(zhí)行棧進(jìn)行執(zhí)行。
異步任務(wù)在瀏覽器中一般是以下:
“棧”是一種數(shù)據(jù)結(jié)構(gòu),是一種線性表。特點(diǎn)為 LIFO,即先進(jìn)后出 (last in, first out)。
利用數(shù)組的 push 和 shift 可以實(shí)現(xiàn)壓棧和出棧的操作。
在代碼運(yùn)行的過程中,函數(shù)的調(diào)用會形成一個(gè)由若干幀組成的棧。
function foo(b) {
let a=10;
return a + b + 11;
}
function bar(x) {
let y=3;
return foo(x * y);
}
console.log(bar(7))
上面代碼最終會在控制臺打印42,下面梳理一下它的執(zhí)行順序。
對象被分配在堆中,堆是一個(gè)用來表示一大塊(通常是非結(jié)構(gòu)化的)內(nèi)存區(qū)域的計(jì)算機(jī)術(shù)語。
首先,stack 是有結(jié)構(gòu)的,每個(gè)區(qū)塊按照一定次序存放,可以明確知道每個(gè)區(qū)塊的大小;heap 是沒有結(jié)構(gòu)的,數(shù)據(jù)可以任意存放。因此,
stack 的尋址速度要快于 heap。
其次,每個(gè)線程分配一個(gè) stack,每個(gè)進(jìn)程分配一個(gè) heap,也就是說,stack 是線程獨(dú)占的,heap 是線程共用的。
此外,stack 創(chuàng)建的時(shí)候,大小是確定的,數(shù)據(jù)從超過這個(gè)大小,就發(fā)生 stack overflow 錯誤,而 heap 的大小是不確定的,
需要的話可以不斷增加。
public void Method1()
{
int i=4;
int y=2;
class1 cls1=new class1();
}
上面代碼這三個(gè)變量和一個(gè)對象實(shí)例在內(nèi)存中的存放方式如下。
從上圖可以看到,i、y和cls1都存放在stack,因?yàn)樗鼈冋加脙?nèi)存空間都是確定的,而且本身也屬于局部變量。但是,cls1指向的對象實(shí)例存放在heap,因?yàn)樗拇笮〔淮_定。作為一條規(guī)則可以記住,所有的對象都存放在heap。
接下來的問題是,當(dāng)Method1方法運(yùn)行結(jié)束,會發(fā)生什么事?
回答是整個(gè)stack被清空,i、y和cls1這三個(gè)變量消失,因?yàn)樗鼈兪蔷植孔兞浚瑓^(qū)塊一旦運(yùn)行結(jié)束,就沒必要再存在了。而heap之中的那個(gè)對象實(shí)例繼續(xù)存在,直到系統(tǒng)的垃圾清理機(jī)制(garbage collector)將這塊內(nèi)存回收。因此,一般來說,內(nèi)存泄漏都發(fā)生在heap,即某些內(nèi)存空間不再被使用了,卻因?yàn)榉N種原因,沒有被系統(tǒng)回收。
隊(duì)列是一種數(shù)據(jù)結(jié)構(gòu),也是一種特殊的線性表。特點(diǎn)為 FIFO,即先進(jìn)先出(first in, first out)
利用數(shù)組的 push 和 pop 可實(shí)現(xiàn)入隊(duì)和出隊(duì)的操作。
事件循環(huán)和事件隊(duì)列的維護(hù)是由事件觸發(fā)線程控制的。
事件觸發(fā)線程線程同樣是由瀏覽器渲染引擎提供的,它會維護(hù)一個(gè)事件隊(duì)列。
js 引擎遇到上文所列的異步任務(wù)后,會交個(gè)相應(yīng)的線程去維護(hù)異步任務(wù),等待某個(gè)時(shí)機(jī),然后由事件觸發(fā)線程將異步任務(wù)對應(yīng)的回調(diào)函數(shù)加入到事件隊(duì)列中,事件隊(duì)列中的函數(shù)等待被執(zhí)行。
js 引擎在執(zhí)行過程中,遇到同步任務(wù),會將任務(wù)直接壓入執(zhí)行棧中執(zhí)行,當(dāng)執(zhí)行棧為空(即 js 引擎線程空閑), 事件觸發(fā)線程 會從事件隊(duì)列中取出一個(gè)任務(wù)(即異步任務(wù)的回調(diào)函數(shù))放入執(zhí)行在棧中執(zhí)行。
執(zhí)行完了之后,執(zhí)行棧再次為空,事件觸發(fā)線程會重復(fù)上一步的操作,再從事件隊(duì)列中取出一個(gè)消息,這種機(jī)制就被稱為 事件循環(huán) (Event Loop)機(jī)制。
為了更好地理解Event Loop,請看下圖(轉(zhuǎn)引自Philip Roberts的演講《Help, I'm stuck in an event-loop》)。
例子代碼:
console.log('script start')
setTimeout(()=> {
console.log('timer 1 over')
}, 1000)
setTimeout(()=> {
console.log('timer 2 over')
}, 0)
console.log('script end')
// script start
// script end
// timer 2 over
// timer 1 over
模擬 js 引擎對其執(zhí)行過程:
此時(shí),執(zhí)行棧為空,js 引擎線程空閑。便從事件隊(duì)列中讀取任務(wù),此時(shí)隊(duì)列如下:
注意點(diǎn):
上面,timer 2 的延時(shí)為 0ms,HTML5標(biāo)準(zhǔn)規(guī)定 setTimeout 第二個(gè)參數(shù)不得小于4(不同瀏覽器最小值會不一樣),不足會自動增加,所以 "timer 2 over" 還是會在 "script end" 之后。
就算延時(shí)為0ms,只是 time 2 的回調(diào)函數(shù)會立即加入事件隊(duì)列而已,回調(diào)的執(zhí)行還是得等到執(zhí)行棧為空時(shí)執(zhí)行。
在 ES6 新增 Promise 處理異步后,js 執(zhí)行引擎的處理過程又發(fā)生了新的變化。
看代碼:
console.log('script start')
setTimeout(function() {
console.log('timer over')
}, 0)
Promise.resolve().then(function() {
console.log('promise1')
}).then(function() {
console.log('promise2')
})
console.log('script end')
// script start
// script end
// promise1
// promise2
// timer over
這里又新增了兩個(gè)新的概念, macrotask (宏任務(wù))和 microtask (微任務(wù))。
所有的任務(wù)都劃分到宏任務(wù)和微任務(wù)下:
js 引擎首先執(zhí)行主代碼塊。
執(zhí)行棧每次執(zhí)行的代碼就是一個(gè)宏任務(wù),包括任務(wù)隊(duì)列(宏任務(wù)隊(duì)列)中的。執(zhí)行棧中的任務(wù)執(zhí)行完畢后,js 引擎會從宏任務(wù)隊(duì)列中去添加任務(wù)到執(zhí)行棧中,即同樣是事件循環(huán)的機(jī)制。
當(dāng)在執(zhí)行宏任務(wù)遇到微任務(wù) Promise.then 時(shí),會創(chuàng)建一個(gè)微任務(wù),并加入到微任務(wù)隊(duì)列中的隊(duì)尾。
微任務(wù)是在宏任務(wù)執(zhí)行的時(shí)候創(chuàng)建的,而在下一個(gè)宏任務(wù)執(zhí)行之前,瀏覽器會對頁面重新渲染(task >> render >> task(任務(wù)隊(duì)列中讀取))。 同時(shí),在上一個(gè)宏任務(wù)執(zhí)行完成后,頁面渲染之前,會執(zhí)行當(dāng)前微任務(wù)隊(duì)列中的所有微任務(wù)。
所以上述代碼的執(zhí)行過程就可以解釋了。
js 引擎執(zhí)行 promise.then 時(shí),promise1、promise2 被認(rèn)為是兩個(gè)微任務(wù)按照代碼的先后順序被加入到微任務(wù)隊(duì)列中,script end執(zhí)行后,棧空。
此時(shí)當(dāng)前宏任務(wù)(script 主代碼塊)執(zhí)行完畢,并不從當(dāng)前宏任務(wù)隊(duì)列中讀取任務(wù)。而是立馬清空當(dāng)前宏任務(wù)所產(chǎn)生的微任務(wù)隊(duì)列。將兩個(gè)微任務(wù)依次放入執(zhí)行棧中執(zhí)行。執(zhí)行完畢,打印 promise1、promise2。棧空。 此時(shí),第一輪事件循環(huán)結(jié)束。
緊接著,再去讀取宏任務(wù)隊(duì)列中的任務(wù),time over 被打印。棧空。
因此,宏任務(wù)和微任務(wù)的執(zhí)行機(jī)制如下:
因?yàn)?async 和 await 本質(zhì)上還是基于 Promise 的封裝,而 Promise 是屬于微任務(wù)的一種。所以使用 await 關(guān)鍵字與 Promise.then 效果類似:
setTimeout(_=> console.log(4))
async function main() {
console.log(1)
await Promise.resolve()
console.log(3)
}
main()
console.log(2)
// 1
// 2
// 3
// 4
async 函數(shù)在 await 之前的代碼都是同步執(zhí)行的, 可以理解為 await 之前的代碼都屬于 new Promise 時(shí)傳入的代碼,await 之后的所有代碼都是 Promise.then 中的回調(diào),即在微任務(wù)隊(duì)列中。
參考:
原文作者:大芒果哇
原文地址:https://www.cnblogs.com/shenggao/p/13799566.html
前端開發(fā)來說,通過動畫來提升交互效果是很常見的。在很早以前,做web動畫主要通過javascript或者jquery或者flash這樣的手段,非常麻煩,自打有了ccs3,做動畫就太方便了,只需幾行css代碼就可以搞定。
這里我們就演示一個(gè)常見的循環(huán)滾動效果,任務(wù)是這樣:先準(zhǔn)備一個(gè)圖片,平鋪到頁面上充滿整個(gè)屏幕,然后就讓畫面一直向上循環(huán)滾動,形成無邊無際的感覺。
雖然可以從網(wǎng)上搜到一些類似的代碼,但是魚龍混雜,無關(guān)緊要的代碼非常多,不夠純粹。如果要弄明白動畫的原理,只有自己動手做一遍才能真正消化吃透。所以我們來一步步原創(chuàng)這個(gè)代碼,排除所有不必要的基礎(chǔ)樣式,只說要點(diǎn),3個(gè)步驟你就可以完全掌握其精髓!
第一步:布局
首先,滾動的圖片需要放在一個(gè)容器里,一行html代碼即可完成:
第二步:把圖片放進(jìn)容器
css中body的邊界設(shè)為0,把容器設(shè)高度100%以充滿屏幕,再調(diào)用背景圖pic.png
第三部:讓畫面動起來
咱不做標(biāo)題黨,循環(huán)滾動靠的就是3行css動起來的。
先是1行 -webkit-animation屬性:4個(gè)參數(shù)分別表示:動畫名稱scroll,1秒時(shí)長,移動速度為線性的,無限循環(huán)。
然后是對應(yīng)的關(guān)鍵幀 @-webkit-keyframes 屬性,這是自己定義的動畫規(guī)則,只需寫2行規(guī)則即可:
原理:動畫就是畫從一個(gè)地方動到另一個(gè)地方。對普通滾動效果來說,有起點(diǎn)和終點(diǎn)這兩個(gè)節(jié)點(diǎn)的位置就夠了。所以我們用0%和100%分別表示起點(diǎn)和終點(diǎn),指定2個(gè)背景圖的xy位置坐標(biāo)即可。圖片會在規(guī)定時(shí)間內(nèi)從起點(diǎn)移動到終點(diǎn),并循環(huán)下去,數(shù)值是負(fù)表示是向上移動。320px正好是圖片的高度,這樣循環(huán)的時(shí)候是無縫銜接的。
好了,最終完整的代碼如下,是不是很精練呢?保存成 index.html 即可
代碼寫完了,還要記得在當(dāng)前目錄要有pic.png這個(gè)圖片哦,我隨便畫了幾筆,絕無觀賞性,建議自己找個(gè)好看點(diǎn)的圖片來代替。
現(xiàn)在用瀏覽器打開index.html即可看到效果,比較魔性的地方在于,如果你盯著看久了,關(guān)閉窗口以后會出現(xiàn)幻覺,仿佛整個(gè)顯示器都在向上飛,哈哈!
最后我們來說說瀏覽器兼容性問題:
大家可能注意到了,前面那2個(gè)古怪的 -webkit-animation, @-webkit-keyframes 這里的-webkit-其實(shí)是一個(gè)前綴,animation和@keyframes才是CSS的標(biāo)準(zhǔn)屬性。
當(dāng)加上-webkit-后,就形成了一個(gè)針對特殊瀏覽器的專有屬性,表示用在谷歌的chrome和蘋果的safari瀏覽器上。此外還有-moz前綴代表針對firefox瀏覽器的私有屬性。
所以我們在用到css3的一些特性的時(shí)候,經(jīng)常使用一大堆的重復(fù)性的代碼,比如我們今天的這個(gè)代碼,有人會寫成這個(gè)樣子:
一個(gè)簡單的動畫就要寫這么多冗余的代碼,為的只是支持一些舊的瀏覽器,有必要嗎?為什么在這個(gè)例子中我們僅僅采用了-webkit-而沒有使用其它專有屬性呢?
因?yàn)楝F(xiàn)在已經(jīng)是2019年了!谷歌蘋果的瀏覽器是主流,占據(jù)了絕大部分,而其它小眾瀏覽器也大多能夠兼容他們,在版本上,大部分人安裝瀏覽器是直接下載新版本安裝使用,而非找出家里陳年的老軟盤、老光盤去安裝,家中的老電腦也早已升級不知多少回了,所以也幾乎沒有機(jī)會使用低版本的瀏覽器了!
至于微軟的IE,就更別提了,IE9以前不支持動畫的,只能用js或者jquery來寫動畫,直到IE10才支持css動畫,隨后IE被放棄,主推Edge,搞了幾天越來越頭大干脆也放棄,現(xiàn)在直接使用chrome內(nèi)核了,所以針對ie的兼容性除非有特殊要求已經(jīng)無需考慮。
你在網(wǎng)上能看到的范例代碼,如果有寫成那么復(fù)雜臃腫的,估計(jì)也都是3-5年前發(fā)的老文,或者抄來抄去不做思考的搬磚工留下的“初學(xué)者”筆記。
我們不仿測試一下幾款主流瀏覽器的情況看看,結(jié)論:
測試結(jié)果表明,-webkit-的寫法在4款不同內(nèi)核的瀏覽器上都能正常使用,所以我們的代碼因此能得以簡化。
當(dāng)然,這個(gè)例子也有局限性,比如你看,只有蘋果safari不支持標(biāo)準(zhǔn)寫法,萬一將來他改邪歸正了呢?畢竟標(biāo)準(zhǔn)寫法才是眾望所歸不是?使用針對個(gè)別瀏覽器的私有屬性寫法,雖可用但畢竟有些怪怪的,將來怎么樣還很難說呢。這樣看來,如果使用古老的處理辦法,重復(fù)N次為每個(gè)專屬瀏覽器各寫一份代碼,除了辣眼睛也真沒什么錯。
瀏覽器的兼容問題涉及面實(shí)在是非常廣,三言兩語還真說不完,以后會專門來講。
*請認(rèn)真填寫需求信息,我們會在24小時(shí)內(nèi)與您取得聯(lián)系。