摘要:最近在開發一個長圖文預覽項目,主要用在手機端瀏覽主要在微信端。大概的實現是首屏開始顯示接下來首屏后面的圖片就全部扔給瀏覽器去加載了。
最近在開發一個長圖文預覽項目,主要用在手機端瀏覽(主要在微信端)。這項目其實就是一個手機網頁,把數據中的文本和圖片等元素渲染出來即可。這樣的項目很常見,包括微信內公眾號的文章etc.這個項目很簡單,但非常頭疼的一個問題是對圖片的懶加載處理。(下面討論的加載策略暫且都是針對圖片)
前置條件:假定項目數據是一個數組,數組元素都是圖片,并且指定了圖片在屏幕中的left和top。
我們最開始想到的處理方式是:優先考慮首屏體驗。
取得數據后,首屏先呈現Loading狀態。通過屏幕的高度H和圖片的top,得到首屏的圖片,并對其每一個圖片的onload和onerror事件綁定回調。當回調全都執行完成之后便將首屏Loading狀態移除,呈現首屏的圖片。大概的實現是:
firstScreenPromises = firstScreenImgs.map((img) => { return new Promise((resolve, reject) => { let image = new Image() image.src = img.imgSrc image.onload = image.onerror = resolve }) }) Promise.all(firstScreenPromises).then(data => { // 首屏開始顯示 })
接下來首屏后面的圖片就全部扔給瀏覽器去加載了。
上面首屏顯示優化自然ok,不過對后面屏幕圖片的顯示策略自然是不太好的。于是考慮分屏加載,一屏一屏加載圖片。
// 分屏 screenBox = {} H = screen.height for (let i = 0; i < imgs.length; i += 1) { screenNum = Math.floor(imgs.top / H) screenBox[screenNum] = screenBox[screenNum] || [] screenBox[screenNum].push(imgs[i]) } indexs = Object.keys(screenBox) ----------上邊代碼塊 (X) 繼續給下一塊代碼使用——------------ loadNext() // 分屏按序加載 function loadNext() { if (!indexs.length) return screenBox[indexs[0]].map(img=>{ // 同首屏firstScreenPromises }).then(data=>{ // load完后回調該函數繼續load下一屏 indexs.shift() loadNext() }) }
上面優化點在于按序分屏加載圖片,這適合用戶慢慢往下看的情況,但是會有兩個弊端。
一是:如果用戶突然猛翻到頁面較后的位置,此時如果還在加載前面某屏的圖片,那用戶需要等待。
二是:如果頁面圖片元素非常多,屏幕數很多,會消耗許多流量,也許用戶不想看到最后咧。
于是考慮控制預加載的屏幕數,用戶看屏幕所時處的屏幕數為N,預加載N+1,N+2....N+M,最多預加載M屏。同時監聽屏幕滾動,通過滾動的高度算出用戶所處的屏幕數。
....上邊代碼塊(X)..... loadNext(0) // 初始化load首屏 window.onscroll = ()=>{ getViewScreenIndex = function() { // 滾動監聽求出用戶視野所處的屏幕數(若處在a,a+1,取a) return ... } loadNext(getViewScreenIndex()) } // 加載第N屏,加載完繼續加載到第N+M屏 function loadNext(N) { hasLoad = 0 function load() { if (hasLoad == M) { // 已經加載到N+M屏,停止預加載 return } hasLoad++ if (indexs.indexOf(N) > -1) { screenBox[indexs[0]].map(img=>{ // 同首屏firstScreenPromises }).then(data=>{ // load完后回調該函數繼續load下一屏 indexs.splice(indexs.indexOf(N), 1) load() }) } else { load() } } }
最后一個優化點:假設正在load第1屏(接下來會預加載第2,3屏),此時屏幕滾動到了第4屏(將會預加載第5,6屏)。此時是否還有必要繼續去加載第2,3屏?我覺得是沒必要的,用戶更有可能會繼續往后翻。所以此時我會取消掉2,3屏的預加載(當然,如果此時正在預加載第2屏,那只會取消掉第3屏的加載)。
這一塊的代碼,加上一些細節處理,可以到我的github lazyloader看看。
總結:目前能考慮到的上邊策略為的是提升用戶體驗(預加載),同時不會去消耗太多流量(限制預加載的數目)。但我相信還會有更加優化的策略,希望能得到高人的指點,那就真的灰常感激啦!
同時,這里邊還會遇到一些兼容上的坑。比如:此處我所用到的滾動監聽是window.onscroll。這個監聽事件在不同設備上的表現非常不一樣,會使得這里的加載策略不一定能使所有的設備都體驗不錯。
android的(不確定是不是所有)window.onscroll會在手指按著屏幕拖動時觸發,以及屏幕滾動停止的時候觸發;而ios的則是只在屏幕停止滾動的時候才會觸發。這兩者,在松開手后屏幕滾動時都不會觸發onscroll事件。
目前還沒想到比較好的兼容策略,希望有人能提供好的資料和想法借鑒借鑒,感激涕零。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80189.html
摘要:虛擬列表的實現有多種方案,本文以組件為基礎進行分析。常見的無限滾動便是延遲渲染的一種實現,而虛擬列表則是按需渲染的一種實現。接下來,本文會簡單介紹虛擬列表的一種實現方案。實現本章節將會創建一個組件,并結合代碼,慢慢梳理虛擬列表的實現。 在 列表數據的展示優化 一文中,提到了對于列表形態的數據展示的按需渲染。這種方式是指根據容器元素的高度以及列表項元素的高度來顯示長列表數據中的某一個部分...
摘要:商品詳情頁上拉查看詳情目錄介紹該庫介紹效果展示如何使用注意要點優化問題部分代碼邏輯參考案例該庫介紹模仿淘寶京東考拉等商品詳情頁分頁加載的效果。 商品詳情頁上拉查看詳情 目錄介紹 01.該庫介紹 02.效果展示 03.如何使用 04.注意要點 05.優化問題 06.部分代碼邏輯 07.參考案例 01.該庫介紹 模仿淘寶、京東、考拉等商品詳情頁分頁加載的UI效果。可以嵌套Recycl...
摘要:對深度學習模型而言,水就是海量的數據。就拿機器識別物體這樣的任務來說,通過數百萬副圖片的訓練,深度學習模型甚至可以超過人的肉眼的識別能力,這確實是人工智能在感知類問題上重要的里程碑。關于深度學習,還有一個有趣的現象。 說到人工智能和機器人,上點兒歲數的碼農們可能對封面這張圖有點印象。不明就里的朋友,可以回去補習一下《編輯部的故事》。我是個二手的人工智能表演藝術家:從博士畢業開始,就在MSRA...
閱讀 3163·2023-04-25 18:22
閱讀 2398·2021-11-17 09:33
閱讀 3320·2021-10-11 10:59
閱讀 3243·2021-09-22 15:50
閱讀 2816·2021-09-10 10:50
閱讀 866·2019-08-30 15:53
閱讀 455·2019-08-29 11:21
閱讀 2919·2019-08-26 13:58