昨天晚上在群里交流各種腦動大開的題目,我順手也提了一個問題: JS如何做“字符分頁“
原意是源於我4年前公司項目,我負責開發1年的樣子,后來各種原因就沒有然后了…
以上圖片是手機上的截圖,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代碼
如果還不了解分欄,則請閱讀如下文章:
- http://www.css3.info/preview/multi-column-layout/
- http://www.w3schools.com/css3/css3_multiple_columns.asp
分欄雖然不如CSS region那樣靈活,但勉強也能夠在不同的欄之間,實現文字的拆分。如果我們把每個欄設置成剛好一頁的話,就初步模擬了分頁的效果。
分欄功能的性能及動態結構
雖然分欄功能初步能夠模擬分頁效果,但還存在着不少問題:
- 分欄形成的頁面,是連續排列的。也就是說,可以支持滑動操作,但並不能支持“翻頁”效果。
- 如果欄目過多時,性能會很差。(大約20~30個欄目會有明顯性能下降)
我們先討論第2個問題,就是如何動態切換分欄中的內容。
由於分欄存在性能問題,因此,我們不可能把很長的內容,全部用分欄排列(請注意,這是我們后面進行了復雜設計的原因。如果分欄沒有性能問題,自然也不需要那么復雜的設計)。
由於性能問題,我們不能把所有需要的內容,全部放在分欄結構中,只能一段一段地顯示在欄目中。也就是說,用於構建分欄的段落,是動態變化的。
在這種情況下,對於分頁的方式而言,最大的問題,是前面的段落,會影響后面的段落的排列。
考慮如下圖所示的情況。
圖中兩個段落在分欄狀態下排列
圖中,藍色段落充滿了一個欄后,會擠出一些內容到下一欄。而綠色段落,會從藍色段落結束的地方繼續排列。
現在假設動態切換時,藍色段落被刪除,而在綠色段落后面,增加了紅色段落。此時,不能讓綠色段落從欄首開始排列,必須在綠色段落的開始,給出一個空白的間隔出來,
如圖所示。
圖中紅色段落的排版
也就是說,雖然藍色段落被刪除,但是其對分欄排版的影響,仍然需要計算在內。就上圖來說,第1個欄可以完全忽略,因為不影響后面的排版。第2欄的上半部分,也就是藍色段落的“剩余影響”,在排版仍然要考慮在內。
如何計算每個段落對后面的段落的“剩余影響”呢?幸好在分欄模式下,提供了獲取每個段落的高度的功能,就是用zepto的height()函數就可以獲取高度。獲取了高度之后,除以欄目高度的余數,就是“剩余影響”。
因此,精確地計算出每個段落的高度,就可以實現動態的分欄排版。
以上就是基於對分欄實現排版的理論,之后涉及
- 分欄功能對翻頁的支持
- 分頁的實現
- 翻頁的效果
- 性能優化
等等這些知識點,有空再寫吧!