網(wǎng)頁(yè)展現(xiàn)的更快,官方說(shuō)法叫做首屏繪制,F(xiàn)irst Paint 或者簡(jiǎn)稱(chēng) FP,直白的說(shuō)法叫做白屏?xí)r間,就是從輸入 URL 到真的看到內(nèi)容(不必可交互,那個(gè)叫 TTI, Time to Interactive)之間經(jīng)歷的時(shí)間。當(dāng)然這個(gè)時(shí)間越短越好。
但這里要注意,和首屏相關(guān)的除了 FP 還有兩個(gè)指標(biāo),分別稱(chēng)為 FCP (First Contentful Paint,頁(yè)面有效內(nèi)容的繪制) 和 FMP (First Meaningful Paint,頁(yè)面有意義的內(nèi)容繪制)。雖然這幾個(gè)概念可能會(huì)讓我們繞暈,但我們只需要了解一點(diǎn):首屏?xí)r間 FP 并不要求內(nèi)容是真實(shí)的,有效的,有意義的,可交互的。換言之,隨便 給用戶(hù)看點(diǎn)啥都行。
這就是本文標(biāo)題的玄機(jī)了:“看起來(lái)”。是的,只是看起來(lái)更快,實(shí)際上還是那樣。所以本文并不討論性能優(yōu)化,討論的是一個(gè)投機(jī)取巧的小伎倆,但的確能夠?qū)崒?shí)在在的提升體驗(yàn)。打個(gè)比方,性能優(yōu)化是修煉內(nèi)功,提升你本身的各項(xiàng)機(jī)能;而本文接下來(lái)要討論的是一些招式,能讓你在第一時(shí)間就唬住對(duì)手。
這所謂的招式就是我接下來(lái)要談的內(nèi)容,學(xué)名骨架屏,也叫 Skeleton。你可能沒(méi)聽(tīng)過(guò)這個(gè)名字,但你不可能沒(méi)見(jiàn)過(guò)它。
骨架屏長(zhǎng)什么樣
這種應(yīng)該是最常見(jiàn)的形式,使用各種形狀的灰色矩形來(lái)模擬圖片和文字。有些 APP 也會(huì)使用圓形,但重點(diǎn)都是和實(shí)際內(nèi)容結(jié)構(gòu)近似,不能差距太大。
如果追求效果,還可以在色塊表面添加動(dòng)畫(huà)(如波紋),顯示出一種動(dòng)態(tài)的效果,算是致敬 Loading 了。
在圖片居多的站點(diǎn),這將會(huì)是一個(gè)很好的體驗(yàn),因?yàn)閳D片通常加載較慢。如上圖演示中的占位圖片采用了低像素的圖片,即大體配色和變化是和實(shí)際內(nèi)容一致的。
如果無(wú)法生成這樣的低像素圖片,稍微降級(jí)的方案是通過(guò)算法獲取圖片的主體顏色,使用純色塊占位。
再退一級(jí),還可以使用全站相同的站位圖片,或者直接一個(gè)統(tǒng)一顏色的色塊。雖說(shuō)效果肯定不如上面兩種,但也聊勝于無(wú)。
骨架屏完全是自定義的,想做成什么樣全憑你的想象。你想做圓形的,三角形的,立體的都可以,但“占位”決定了它的特性:它不能太復(fù)雜,必須第一時(shí)間,最快展現(xiàn)出來(lái)。
骨架屏有哪些優(yōu)勢(shì)
大體來(lái)說(shuō),骨架屏的優(yōu)勢(shì)在于:
1、在頁(yè)面加載初期預(yù)先渲染內(nèi)容,提升感官上的體驗(yàn)。
2、一般情況骨架屏和實(shí)際內(nèi)容的結(jié)構(gòu)是類(lèi)似的,因此之后的切換不會(huì)過(guò)于突兀。這點(diǎn)和傳統(tǒng)的 Loading 動(dòng)圖不同,可以認(rèn)為是其升級(jí)版。
3、只需要簡(jiǎn)單的 CSS 支持 (涉及圖片懶加載可能還需要 JS ),不要求 HTTPS 協(xié)議,沒(méi)有額外的學(xué)習(xí)和維護(hù)成本。
4、如果頁(yè)面采用組件化開(kāi)發(fā),每個(gè)組件可以根據(jù)自身狀態(tài)定義自身的骨架屏及其切換時(shí)機(jī),同時(shí)維持了組件之間的獨(dú)立性。
骨架屏能用在哪里
現(xiàn)在的 WEB 站點(diǎn),大致有兩種渲染模式:
前端渲染
由于最近幾年 Angular/React/Vue 的相繼推出和流行,前端渲染開(kāi)始占據(jù)主導(dǎo)。這種模式的應(yīng)用也叫單頁(yè)應(yīng)用(SPA, Single Page Application)。
前端渲染的模式是服務(wù)器(多為靜態(tài)服務(wù)器)返回一個(gè)固定的 HTML。通常這個(gè) HTML 包含一個(gè)空的容器節(jié)點(diǎn),沒(méi)有其他內(nèi)容。之后內(nèi)部包含的 JS 包含路由管理,頁(yè)面渲染,頁(yè)面切換,綁定事件等等邏輯,所以稱(chēng)之為前端渲染。
因?yàn)榍岸艘芾淼氖虑楹芏啵?JS 通常很大很復(fù)雜,執(zhí)行起來(lái)也要花較多的時(shí)間。在 JS 渲染出實(shí)際內(nèi)容之前,骨架屏就是一個(gè)很好的替補(bǔ)隊(duì)員。
后端渲染
在這波前端渲染流行之前,早期的傳統(tǒng)網(wǎng)站采用的模式叫做后端渲染,即服務(wù)器直接返回網(wǎng)站的 HTML 頁(yè)面,已經(jīng)包含首頁(yè)的全部(或絕大部分) DOM 元素。其中包含的 JS 的作用大多是綁定事件,定義用戶(hù)交互后的行為等。少量會(huì)額外添加/修改一些 DOM,但無(wú)礙大局。
此外,前端渲染的模式存在 SEO 不友好的問(wèn)題,因?yàn)樗祷氐?HTML 是一個(gè)空的容器。如果搜索引擎沒(méi)有執(zhí)行 JS 的能力(稱(chēng)為 Deep Render),那它就不知道你的站點(diǎn)究竟是什么內(nèi)容,自然也就無(wú)法把站點(diǎn)排到搜索結(jié)果中去。這對(duì)于絕大部分站點(diǎn)來(lái)說(shuō)是不可接受的,于是前端框架又相繼推出了服務(wù)端渲染(簡(jiǎn)稱(chēng) SSR, Server Side Rendering)模式。這個(gè)模式和傳統(tǒng)網(wǎng)站很接近,在于返回的 HTML 也是包含所有的 DOM,而非前端渲染。而前端 JS 除了綁定事件之外,還會(huì)多做一個(gè)事情叫做“激活”(hydration),這里就不再贅述了。
不論是傳統(tǒng)模式還是 SSR,只要是后端渲染,就不需要骨架屏。因?yàn)轫?yè)面的內(nèi)容直接存在于 HTML,所以并沒(méi)有骨架屏出場(chǎng)的余地。
骨架屏怎么用
討論了一波背景,我們來(lái)看如何使用。首先先無(wú)視具體的實(shí)現(xiàn)細(xì)節(jié),先看思路。
實(shí)現(xiàn)思路
大體分為幾個(gè)步驟:
<html> <head> <style> .skeleton-wrapper { // styles } </style> <!-- 聲明 meta 或者引入其他 CSS --> </head> <body> <div id="app"> <div class="skeleton-wrapper"> <img src="data:image/svg+xml;base64,XXXXXX"> </div> </div> <!-- 引用 JS --> </body> </html>
let app = new Vue({...}) let container = document.querySelector('#app') if (container) { container.innerHTML = '' } app.$mount(container)
僅此兩步,并不牽涉多么復(fù)雜的機(jī)制和高端的 API,因此非常容易應(yīng)用,趕快用起來(lái)!
示例
我編寫(xiě)了一個(gè)示例,用于快速展現(xiàn)骨架屏的效果,代碼在此。
代碼的三個(gè)文件各司其職,配合上面的實(shí)現(xiàn)思路,應(yīng)該還是很好理解的。可以在 這里 查看效果。
因?yàn)檫@個(gè)示例的邏輯太過(guò)簡(jiǎn)單,而實(shí)際的前端渲染框架復(fù)雜得多,包含的功能也不單純是渲染,還有狀態(tài)管理,路由管理,虛擬 DOM 等等,所以文件大小和執(zhí)行時(shí)間都更大更長(zhǎng)。我們?cè)诓榭蠢拥臅r(shí)候,把網(wǎng)絡(luò)調(diào)成 "Fast 3G" 或者 "Slow 3G" 能夠稍微真實(shí)一些。
但匪夷所思的是,對(duì)著這個(gè)地址刷新試幾次,我也基本看不到骨架屏(骨架屏的內(nèi)容是一個(gè)居中的藍(lán)色方形圖片,外加一條白色橫線(xiàn)反復(fù)側(cè)滑的高亮動(dòng)畫(huà))。是我們的實(shí)現(xiàn)思路有問(wèn)題嗎?
瀏覽器的奧秘:減少重排
為了排除肉眼的遺漏和干擾,我們用 Chrome Dev Tools 的 Performance 工具來(lái)記錄剛才發(fā)生了什么,截圖如下:(截圖時(shí)的網(wǎng)絡(luò)設(shè)置為 "Fast 3G")
我們可以很明顯地看到 3 個(gè)時(shí)間點(diǎn):
1、HTML 加載完成了。瀏覽器在解析 HTML 的同時(shí),發(fā)現(xiàn)了它需要引用的 2 個(gè)外部資源 index.js 和 index.css,于是發(fā)送網(wǎng)絡(luò)請(qǐng)求去獲取。
2、獲取成功后,執(zhí)行 JS 并注冊(cè) CSS 的規(guī)則。
3、JS 一執(zhí)行,很自然的渲染出了實(shí)際的內(nèi)容,并應(yīng)用了樣式規(guī)則(隨機(jī)顏色的橫條)。
我們的骨架屏呢?按照預(yù)想,骨架屏應(yīng)該出現(xiàn)在 1 和 2 之間,也就是在獲取 JS 和 CSS 的同時(shí),就應(yīng)該渲染骨架屏了。這也是我們當(dāng)時(shí)把骨架屏的 HTML 注入到 index.html, 還把 CSS 從 index.css 中分離出來(lái)的良苦用心,然而瀏覽器并不買(mǎi)賬。
這其實(shí)和瀏覽器的渲染順序有關(guān)。
相信大家都整理過(guò)行李箱。我們?cè)谡硇欣钕鋾r(shí),會(huì)根據(jù)每個(gè)行李的大小合理安排,大的和小的配合,填滿(mǎn)一層再放上面一層。現(xiàn)在突然有人跑來(lái)跟你說(shuō),你的電腦不用帶了,你要多帶兩件衣服,你不能帶那么多瓶礦泉水。除了想打他之外,為了重新整理行李箱,必然需要把整理好的行李拿出來(lái)再重新放。在瀏覽器中這個(gè)過(guò)程叫做重排 (reflow),而那個(gè)餿主意就是新加載的 CSS。顯而易見(jiàn),重排的開(kāi)銷(xiāo)是很大的。
熟能生巧,箱子理多了,就能想出解決辦法。既然每個(gè) CSS 文件加載都可能觸發(fā)重繪,那我能不能等所有 CSS 加載完了一起渲染呢?正是基于這一點(diǎn),瀏覽器會(huì)等 HTML 中所有的 CSS 都加載完,注冊(cè)完,一起應(yīng)用樣式,力求一次排列完成工作,不要反復(fù)重排。看起來(lái)瀏覽器的設(shè)計(jì)者經(jīng)常出差,因?yàn)檫@是一個(gè)很正確的優(yōu)化思路,但應(yīng)用在骨架屏上就出了問(wèn)題。
我們?yōu)榱吮M早展現(xiàn)骨架屏,把骨架屏的樣式從 index.css 分離出來(lái)。但瀏覽器不知道,它以為骨架屏的 HTML 還依賴(lài) index.css,所以必須等它加載完。而它加載完之后,render.js 也差不多加載完開(kāi)始執(zhí)行了,于是骨架屏的 HTML 又被替換了,自然就看不到了。而且在等待 JS, CSS 加載的時(shí)候依然是個(gè)白屏,骨架屏的效果大打折扣。
所以我們要做的是告訴瀏覽器,你放心大膽的先畫(huà)骨架屏,它和后面的 index.css 是無(wú)關(guān)的。那怎么告訴它呢?
告訴瀏覽器先渲染骨架屏
我們?cè)谝?CSS 時(shí),會(huì)使用 <link rel="stylesheet" href="xxxx> 這樣的語(yǔ)法。但實(shí)際上,瀏覽器還提供了其他一些機(jī)制確保(后續(xù))頁(yè)面的性能,我們稱(chēng)之為 preload,中文叫預(yù)加載。具體來(lái)說(shuō),使用 <link rel="preload" href="xxxx">,提前把后續(xù)要使用的資源先聲明一下。在瀏覽器空閑的時(shí)候會(huì)提前加載并放入緩存。之后再使用就可以節(jié)省一個(gè)網(wǎng)絡(luò)請(qǐng)求。
這看似無(wú)關(guān)的技術(shù),在這里將起到很大的作用,因?yàn)?預(yù)加載的資源是不會(huì)影響當(dāng)前頁(yè)面的。
我們可以通過(guò)這種方式,告訴瀏覽器:先不要管 index.css,直接畫(huà)骨架屏。之后 index.css加載回來(lái)之后,再應(yīng)用這個(gè)樣式。具體來(lái)說(shuō)代碼如下:
<link rel="preload" href="index.css" as="style" onload="this.rel='stylesheet'">
方法的核心是通過(guò)改變 rel 可以讓瀏覽器重新界定 <link> 標(biāo)簽的角色,從預(yù)加載變成當(dāng)頁(yè)樣式。(另外也有文章采用修改 media 的方法,但瀏覽器支持度較低,這里不作展開(kāi)了。我把文章列在最后了)這樣的話(huà),瀏覽器在 CSS 尚未獲取完成時(shí),會(huì)先渲染骨架屏(因?yàn)榇藭r(shí)的 CSS 還是 preload,也就是后續(xù)使用的,并不妨礙當(dāng)前頁(yè)面)。而當(dāng) CSS 加載完成并修改了自己的 rel之后,瀏覽器重新應(yīng)用樣式,目的達(dá)成。
不得不考慮的注意點(diǎn)
事實(shí)上,并不是把 rel="stylesheet" 改成 rel="preload" 就完事兒了。在真正應(yīng)用到生產(chǎn)環(huán)境之前,我們還有很多事情要考慮。
兼容性考慮
首先,在 <link> 內(nèi)部我們使用了 onload,也就是使用了 JS。為了應(yīng)對(duì)用戶(hù)的瀏覽器沒(méi)有開(kāi)啟腳本功能的情況,我們需要添加一個(gè) fallback。(不過(guò)這點(diǎn)對(duì)于單頁(yè)應(yīng)用來(lái)說(shuō)可能也無(wú)所謂,因?yàn)槿绻麤](méi)有腳本,那頁(yè)面實(shí)際內(nèi)容也渲染不出來(lái)的)
<noscript><link rel="stylesheet" href="index.css"></noscript>
其次,rel="preload" 并不是沒(méi)有兼容性問(wèn)題。對(duì)于不支持 preload 的瀏覽器,我們可以添加一些 polyfill 代碼(來(lái)使所有瀏覽器獲得一致的效果。
<script> /*! loadCSS rel=preload polyfill. [c]2017 Filament Group, Inc. MIT License */ (function(){ ... }()); </script>
polyfill 的壓縮代碼可以參見(jiàn) Lavas 的 SPA 模板第 29 行。
加載順序
不同于傳統(tǒng)頁(yè)面,我們的實(shí)際 DOM 是通過(guò) render.js 生成的。所以如果 JS 先于 CSS 執(zhí)行,那將會(huì)發(fā)生跳動(dòng)。(因?yàn)橄蠕秩玖藢?shí)際內(nèi)容卻沒(méi)有樣式,而后樣式加載,頁(yè)面出現(xiàn)很明顯的變化)所以這里我們需要嚴(yán)格控制 CSS 早于渲染。
<link rel="preload" href="index.css" as="style" onload="this.rel='stylesheet';window.STYLE_READY=true;window.mountApp && window.mountApp()">
JS 對(duì)外暴露一個(gè) mountApp 方法用于渲染頁(yè)面(其實(shí)是模擬 Vue 的 mount)
// render.js function mountApp() { // 方法內(nèi)部就是把實(shí)際內(nèi)容添加到 <body> 上面 } // 本來(lái)直接調(diào)用方法完成渲染 // mountApp() // 改成掛到 window 由 CSS 來(lái)調(diào)用 window.mountApp = mountApp() // 如果 JS 晚于 CSS 加載完成,那直接執(zhí)行渲染。 if (window.STYLE_READY) { mountApp() }
如果 CSS 更快加載完成,那么通過(guò)設(shè)置 window.STYLE_READY 允許 JS 加載完成后直接執(zhí)行;而如果 JS 更快,則先不自己執(zhí)行,而是把機(jī)會(huì)留給 CSS 的 onload。
清空 onload
loadCSS 的開(kāi)發(fā)者提出,某些瀏覽器會(huì)在 rel 改變時(shí)重新出發(fā) onload,導(dǎo)致后面的邏輯走了兩次。為了消除這個(gè)影響,我們?cè)僭?onload 里面添加一句 this.onload=null。
最終的 CSS 引用方式
<link rel="preload" href="index.css" as="style" onload="this.onload=null;this.rel='stylesheet';window.STYLE_READY=true;window.mountApp && window.mountApp()"> <!-- 為了方便閱讀,折行重復(fù)一遍 --> <!-- this.onload=null --> <!-- this.rel='stylesheet' --> <!-- window.STYLE_READY=true --> <!-- window.mountApp && window.mountApp() -->
修改后的效果
修改后的代碼在 這里,訪(fǎng)問(wèn)地址在 這里。(為了簡(jiǎn)便,我省去了處理兼容性的代碼,即 <noscript> 和 preload polyfill)
Performance 截圖如下:(依然采用了 "Fast 3G" 的網(wǎng)絡(luò)設(shè)置)
這次在 render.js 和 index.css 還在加載的時(shí)候頁(yè)面已經(jīng)呈現(xiàn)出骨架屏的內(nèi)容,實(shí)際肉眼也可以觀測(cè)到。在截圖的情況下,骨架屏的展現(xiàn)大約持續(xù)了 300ms,占據(jù)整個(gè)網(wǎng)絡(luò)請(qǐng)求的大約一半時(shí)間。
至于說(shuō)為什么不是 HTML 加載完成立馬展現(xiàn)骨架屏,而是還要等大約 300ms 才展現(xiàn),從圖上看是瀏覽器 ParseHTML 所花費(fèi)的時(shí)間,可能在 Dev Tools 打開(kāi)的情況下計(jì)算資源有限,不過(guò)可優(yōu)化空間已經(jīng)不大。(可能簡(jiǎn)化骨架屏的結(jié)構(gòu)能起一些作用吧)
多骨架屏的支持
一般來(lái)說(shuō)一個(gè)站點(diǎn)的所有頁(yè)面不太可能是同一種展示類(lèi)型。例如說(shuō)首頁(yè)和內(nèi)部頁(yè)面就展示風(fēng)格而言會(huì)很有區(qū)別,另外例如列表頁(yè)和搜索頁(yè)比較接近(可能都有列表展示),但和詳情頁(yè)(可能是商品,服務(wù),個(gè)人信息,博客文章等等)就會(huì)很不相同。但單頁(yè)應(yīng)用的 index.html 只有一個(gè),所有的變化都源自前端渲染框架在容器節(jié)點(diǎn)內(nèi)部進(jìn)行改變。所以直接將骨架屏注入到 index.html中會(huì)導(dǎo)致所有的頁(yè)面都用同一個(gè)骨架屏,那就很難達(dá)成“和實(shí)際內(nèi)容結(jié)構(gòu)類(lèi)似”的目標(biāo)了,骨架屏就退化為 Loading 了。
為了要支持多種骨架屏,我們需要在 index.html 里面進(jìn)行判斷邏輯(獨(dú)立于主體 JS 之外),具體來(lái)說(shuō):
1、把所有種類(lèi)的骨架屏的 HTML 和樣式全部寫(xiě)入 index.html
2、在 index.html 底下新增內(nèi)聯(lián)的腳本 <script>,根據(jù)當(dāng)前路由判斷應(yīng)該展示哪一個(gè)骨架屏
這樣會(huì)導(dǎo)致 index.html 體積變大一點(diǎn),但整體感覺(jué)依然是收益大于付出,我認(rèn)為是值得的。
后記
這個(gè)優(yōu)化點(diǎn)最早由我的前同事 xiaop 同學(xué) 在開(kāi)發(fā) Lavas 的 SPA 模板中發(fā)現(xiàn)并完成的,Issue 記錄在此。我在他的基礎(chǔ)上,做了一個(gè)分離 Lavas 和 Vue 環(huán)境并且更直白的例子,讓截圖也盡可能易于理解,方便閱讀。在此非常感謝他的工作!
另外骨架屏的編寫(xiě)我全部采用的是純粹的手寫(xiě) HTML 和 CSS,不止展現(xiàn)邏輯,包括開(kāi)發(fā)流程也是獨(dú)立于單頁(yè)應(yīng)用其他常規(guī)頁(yè)面的。當(dāng)然這可能給開(kāi)發(fā)者帶來(lái)一點(diǎn)不便,所以這時(shí)候需要推出 xiaop 同學(xué)的利器:vue-skeleton-webpack-plugin https://github.com/lavas-project/vue-skeleton-webpack-plugin。它的作用是把骨架屏本身也當(dāng)成一個(gè) Vue 組件,配上單獨(dú)的路由規(guī)則來(lái)統(tǒng)一在 Vue 項(xiàng)目中的開(kāi)發(fā)體驗(yàn),最后使用 webpack 在打包構(gòu)建的時(shí)候加以區(qū)分并注入,對(duì)于使用 Vue + webpack 開(kāi)發(fā)的同學(xué)來(lái)說(shuō)可以一試。
參考文章
轉(zhuǎn)自作者作者:小蘑菇小哥https://zhuanlan.zhihu.com/p/48601348
果圖
思路分析:
1、開(kāi)啟一個(gè)定時(shí)器
方法名:window.setInterval(code,MilliSec),每隔指定的時(shí)間就執(zhí)行code,無(wú)限次執(zhí)行。
2、定時(shí)器函數(shù)主要是用來(lái)執(zhí)行圖片輪播的效果
3、當(dāng)鼠標(biāo)放在圖片上面時(shí),圖片就停止了輪播的效果 清除了定時(shí)器
方法名:window.clearInterval (timer),清除指定的定時(shí)器。
4、當(dāng)鼠標(biāo)離開(kāi)圖片上面時(shí),圖片繼續(xù)在執(zhí)行輪播的效果 重新開(kāi)啟了定時(shí)器功能
5、當(dāng)鼠標(biāo)放在li標(biāo)簽上面時(shí),圖片就停止了輪播的效果 清除了定時(shí)器
6、當(dāng)鼠標(biāo)放在li標(biāo)簽上面時(shí),還會(huì)顯示li標(biāo)簽上面對(duì)應(yīng)的數(shù)字的圖片
7、當(dāng)鼠標(biāo)離開(kāi)li標(biāo)簽上面時(shí),圖片就會(huì)繼續(xù)開(kāi)始輪播的效果 重新開(kāi)啟了定時(shí)器功能
8、li標(biāo)簽上面的高亮效果,它是隨著圖片滾動(dòng)而滾動(dòng)。
HTML代碼
<body> <div id="content"> <!--輪換顯示的橫幅廣告圖片--> <div class="scroll_top"></div> <div class="scroll_mid"> <img src="images/dd_scroll_1.jpg" alt="輪換顯示的圖片廣告" id="dd_scroll" οnmοuseοver="stopScroll()" οnmοuseοut="goon()"/> <div id="scroll_number"> <ul> <li class="scroll_number_over" οnmοuseοver="stopScroll(1)" οnmοuseοut="goon()">1</li> <li οnmοuseοver="stopScroll(2)" οnmοuseοut="goon()">2</li> <li οnmοuseοver="stopScroll(3)" οnmοuseοut="goon()">3</li> <li οnmοuseοver="stopScroll(4)" οnmοuseοut="goon()">4</li> <li οnmοuseοver="stopScroll(5)" οnmοuseοut="goon()">5</li> <li οnmοuseοver="stopScroll(6)" οnmοuseοut="goon()">6</li> </ul> </div> </div> <div class="scroll_end"></div> </div> </body>
JS代碼
<script type="text/javascript"> window.οnlοad=function(){ timer=setInterval("imgScroll()",500); var scroll_number=document.getElementById('scroll_number'); scrLi=scroll_number.getElementsByTagName('li'); scrLiLen=scrLi.length; } var n=2; function imgScroll(){ for(var i=0;i<scrLiLen;i++){ scrLi[i].className=""; } scrLi[n-1].className="scroll_number_over"; var imgObj=document.getElementById('dd_scroll'); imgObj.src="images/dd_scroll_"+n+".jpg"; n++; if(n>6){ n=1; } } function stopScroll(imgN){ if(imgN){ n=imgN; imgScroll(); } clearInterval(timer); } function goon(){ timer=setInterval('imgScroll()',500); } </script>
以上就是輪播圖怎么做的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注其它相關(guān)文章!
更多技巧請(qǐng)《轉(zhuǎn)發(fā) + 關(guān)注》哦!
推薦一波前端開(kāi)發(fā)必備插件,絕對(duì)可以提高你的生產(chǎn)力,剩下來(lái)的時(shí)間來(lái) mo魚(yú),豈不美哉
插件名:別名路徑跳轉(zhuǎn)
使用說(shuō)明: 別名路徑跳轉(zhuǎn)插件,支持任何項(xiàng)目,
使用場(chǎng)景: 當(dāng)你在開(kāi)發(fā)頁(yè)面時(shí), 想點(diǎn)擊別名路徑導(dǎo)入的組件時(shí)(演示如下)
test01
img
img
image-20211001221922170
Screenshot
test02
image-20211001222515014
test03.gif
image-20211001223256342
Live Server Demo VSCode
demo
test04.gif
typing a dollar sign then open curly brace within a string converts the quotes to backticks
預(yù)覽
image-20211001225347827
test05.gif
image-20211002094809502
img
img
img
image-20211002093516003
image-20211002093806553
image-20211002093922498
image-20211002094123650
image-20211002095626877
img
Introduction
Introduction
image-20211002103141474
關(guān)于本文
https://segmentfault.com/a/1190000040766151
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。