前端實現網路閱讀軟體之分頁原理與演算法(一)

發表於2016-03-23

昨天晚上在群裡交流各種腦動大開的題目,我順手也提了一個問題: JS如何做“字元分頁“

原意是源於我4年前公司專案,我負責開發1年的樣子,後來各種原因就沒有然後了…

http://reader.appcarrier.com/

image image  image

以上圖片是手機上的截圖,Metro風格當前可是風靡一時,軟體本身是類似現在的”追書神器”

通過書名,在網路上搜尋到對應的內容,之後儲存到本地資料庫。在通過JS獲取資料再處理

自己裝好測了下,貌似下載伺服器已經掛了~

 

程式採用PhoneGap打包的,資料採集是用底層完成的,其餘的都是通過前端處理

規定:採集到一本書內容,按照書的章節分資料塊,寫入到本地資料庫中,資料庫可以用SQLite,webkit是支援的

前端層面需要處理的幾個重要問題:

  • 字元分頁:一個頁面到底可以容納多少字元(文字,符號,空格等等)
  • 效能問題:如何快速生成指定頁面
  • 模擬翻頁:類似ibooks翻頁效果頁正反頁面都有文字

 

由於時間太久了,我也沒仔細去查閱程式碼了,這裡只能憑記憶描述下

 

原理:

要實現類似於圖書的效果,首先要進行的,就是分頁操作。也就是說,需要把一段長長的文字,分解成若干個頁面。

 

分頁背景知識:

表面上來看,分頁操作並不複雜,但實際上分頁是非常複雜的功能,這個想靠js去計算文字佔用的空間,難,非常難

我在問的時候,大家腦洞開啟,比如:用一個不換行的寬度100%的容器,計算什麼時候scrollwidth 大於width,那麼就可以計算出  標點需要多少個填滿,等等之類的答案

現在站在我的理解層次簡單描述下:

純文字:

純文字是最簡單的情況。純文字的高度是固定的,因此,只要能計算出每一行的高度,就可以進行分頁。但是,中文排版也不是一件簡單的事情,因為中文的標點是很有講究的:

  • 某些標點不能出現在行的開頭,例如“逗號”就不應該出現在行首。有些標點不能出現在行的結尾,例如“正引號”就不應該出現在行的結尾。這個叫做標點的“避頭尾”。
  • 如果出現連續的標點,例如冒號後面跟著引號,那麼這兩個標點不應該佔據2個字元的位置,而應該合併起來佔據一個字元的位置。這個叫做標點的“壓縮”。

html格式:

對於html格式,情況就複雜很多,因此此時行距不固定了,段前、段後間距可能是任意值,而且每行的文字的字型、字號都有可能不一樣,這樣,計算每一行的高度,就要考慮到種種細微的因素。

如果中間再有影象,情況就會進一步複雜。影象的高度,影象和文字的邊距等等。

伺服器計算:

如果在伺服器裡面,提前計算好分頁呢?也有問題, 因為要適合不同的手機解析度,軟體本身還可以設定字型的大小,等等

 

因此:

  •  即使是純文字,高度的計算也是有一個複雜度的。當然,有些軟體可能不考慮這些中文特性,胡亂計算。
  •  不管採用底層的Java語言,還是採用客戶端的Javascript語言,要實現精緻的分頁演算法都是很難的。
  •  可能有人想問,如果分頁分得不好會出現什麼情況。最常見的,是最下面以行,某些文字只能顯示“半行”。而且顯而易見,出現半行的機率,遠遠大於正好是整行的機率。

總結:通過純理論去計算分頁,和自己寫一個文字排版軟體區別已經不大了,這絕不是短期的工作能夠完成的。況且我也寫不出~

 

HTML對分頁的支援

HTML並不直接支援分頁。

Adobe正在建議一個新的CSS樣式,稱為CSS Region(http://www.adobe.com/devnet/html5/articles/css3-regions.html)。

如果這個功能開發成功,就能實現類似於排版軟體的排版效果。據說這個功能在新的Chrome測試版中正在開發中,但何時能投入使用並穩定執行,還是未知數。

html5新增加了一個功能,就是分欄(columns)。分欄功能可以製作類似於Word中的分欄效果

html5的分欄效果以及CSS程式碼

clip_image002

如果還不瞭解分欄,則請閱讀如下文章:

分欄雖然不如CSS region那樣靈活,但勉強也能夠在不同的欄之間,實現文字的拆分。如果我們把每個欄設定成剛好一頁的話,就初步模擬了分頁的效果

 

分欄功能的效能及動態結構

雖然分欄功能初步能夠模擬分頁效果,但還存在著不少問題:

  1. 分欄形成的頁面,是連續排列的。也就是說,可以支援滑動操作,但並不能支援“翻頁”效果。
  2. 如果欄目過多時,效能會很差。(大約20~30個欄目會有明顯效能下降)

我們先討論第2個問題,就是如何動態切換分欄中的內容。

由於分欄存在效能問題,因此,我們不可能把很長的內容,全部用分欄排列(請注意,這是我們後面進行了複雜設計的原因。如果分欄沒有效能問題,自然也不需要那麼複雜的設計)。

由於效能問題,我們不能把所有需要的內容,全部放在分欄結構中,只能一段一段地顯示在欄目中。也就是說,用於構建分欄的段落,是動態變化的

在這種情況下,對於分頁的方式而言,最大的問題,是前面的段落,會影響後面的段落的排列。

考慮如下圖所示的情況。

clip_image001

圖中兩個段落在分欄狀態下排列

圖中,藍色段落充滿了一個欄後,會擠出一些內容到下一欄。而綠色段落,會從藍色段落結束的地方繼續排列。

現在假設動態切換時,藍色段落被刪除,而在綠色段落後面,增加了紅色段落。此時,不能讓綠色段落從欄首開始排列,必須在綠色段落的開始,給出一個空白的間隔出來,

如圖所示。

clip_image002[5]

圖中紅色段落的排版

也就是說,雖然藍色段落被刪除,但是其對分欄排版的影響,仍然需要計算在內。就上圖來說,第1個欄可以完全忽略,因為不影響後面的排版。第2欄的上半部分,也就是藍色段落的“剩餘影響”,在排版仍然要考慮在內。

如何計算每個段落對後面的段落的“剩餘影響”呢?幸好在分欄模式下,提供了獲取每個段落的高度的功能,就是用zepto的height()函式就可以獲取高度。獲取了高度之後,除以欄目高度的餘數,就是“剩餘影響”。

因此,精確地計算出每個段落的高度,就可以實現動態的分欄排版。

 

以上就是基於對分欄實現排版的理論,之後涉及

  • 分欄功能對翻頁的支援
  • 分頁的實現
  • 翻頁的效果
  • 效能優化

等等這些知識點,等下一節釋出吧

相關文章