前端实现网络小说阅读器
昨天晚上在群里交流各种脑动大开的题目,我顺手也提了一个问题: 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()函数就可以获取高度。获取了高度之后,除以栏目高度的余数,就是“剩余影响”。
因此,精确地计算出每个段落的高度,就可以实现动态的分栏排版。
以上就是基于对分栏实现排版的理论,之后涉及
- 分栏功能对翻页的支持
- 分页的实现
- 翻页的效果
- 性能优化
等等这些知识点,有空再写吧!