javascript小说阅读器分页算法的实现

        好久好久不写代码了,也好久没更新博客了,这次就和大家分享一个电子书阅读器分页的算法吧。

        像一些主流的阅读器,如QQ阅读、iReader等,都实现了txt文档分页显示的功能,打开一个txt文档可以快速把文档分割成若干页,每页文字正好铺满屏幕,点击翻屏显示下一页,这样不用操作滚动条,阅读体验更好。那么如何实现txt文件的快速分页呢?如果计算屏幕大小和字体大小算出一屏可以有多少字,这样肯定不行,因为有英文和其他字符比如中文和标点,还有换行回车,所以肯定要先设置一块和显示屏一样大的容器(可变高度),首先根据屏幕大小和字体大小算出一屏可以容纳的字数最大值,从文件读出这些字数,将这段文字写入设置好的那个容器,如果容器高度大于屏幕高度,则减少文字读取的长度,再次试探容器高度是否大于屏幕高度,直到容器高度和屏幕高度一致,则当前屏幕应该显示的内容就是容器内的内容。要是一个字一个字试探效率太低,我改进了算法,每次减去20字,当减到容器高度小于屏幕高度时,在反向微调,添加一个字,这样分页的效率大大提高,点击显示下一页看不出延迟。核心代码如下图

javascript小说阅读器分页算法的实现_第1张图片

        前些日子写了个阅读器demo,只是实现了文件浏览,打开文件和文件分页功能,阅读器主题设置,阅读历史存档等还没做,因为这些都比较简单了,懒得去做了,大家有兴趣可以在此基础上修改成成品。下面先上效果图再上完整代码,这个是用xml做的视图层,JScript做的逻辑层,可以运行于windows7及以上系统。

首先是效果图:

javascript小说阅读器分页算法的实现_第2张图片

主题设置目前只做了字体和背景颜色的设置,所有的设置都存在一个对象之中,可以通过读写json文件存储,读写我已经封装到IOMod这个模块了,可以直接拿来用getSetting和setSetting两个方法。

javascript小说阅读器分页算法的实现_第3张图片

最后编译完成的文件如下:

javascript小说阅读器分页算法的实现_第4张图片

下面上代码:首先是视图模块viewMod.js

/*应用程序界面模块*/
this.viewMod={
	root:"F:\\电子书",totalNum:0,ramPoint:0,textData:"",S:{},screen:"",
	init:function(screen){
		this.S=ioMod.getSetting();
		/*读取配置,fontSize,color,background,lastRead*/
		var SC=document.querySelector(screen);
		SC.style.fontSize=this.S.fontSize+"px";
		SC.style.color=this.S.color;
		document.body.style.background=this.S.background;
		var SC_BAR=document.querySelector("readerViewBar");
		SC_BAR.style.borderBottom="1px solid "+this.S.color;
		SC_BAR.style.color=this.S.color;
		this.screenX=SC.offsetWidth;
		this.screenY=SC.offsetHeight;
		this.screen=screen;
	},
	print:function(item,data){
		document.querySelector(item).innerHTML=data;
	},
	printT:function(item,data){
		document.querySelector(item).innerText=data;
	},
	fileList:function(folder){
		folder=(folder==undefined)?this.root:folder;
		/*文件夹和电子书列表的显示*/
		var lastFolder;
		if(folder.indexOf("\\")<0){
			lastFolder=folder;
		}else{
			lastFolder=folder.split("\\");
			lastFolder.splice(lastFolder.length-1,1);
			lastFolder=lastFolder.join("\\");
		}
		var view="<<返回上级";
		var data=ioMod.getFolderList(folder);
		for(var i in data){
			view+="";
			view+=data[i].name;
			view+="";
		}
		data=ioMod.getBookList(folder);
		for(var i in data){
			view+="";
			view+=data[i].name;
			view+="";
		}
		this.print("bookFileList",view);
	},
	openBook:function(url,name){
		/*打开文件*/
		this.ramPoint=0;
		this.textData=ioMod.openFile(url);
		var data=this.getTextData("next");
		this.printT(this.screen,data);
		this.printT("titleBar","文件->"+name);
	},
	getTextData:function(direction){
		/*分页*/
		if(document.querySelector("SYS_TEXT_SCREEN")==null){
			var SYS_TEXT_SC=document.createElement("SYS_TEXT_SCREEN");
			SYS_TEXT_SC.style.position="absolute";
			SYS_TEXT_SC.style.top="0px";
			SYS_TEXT_SC.style.left="0px";
			SYS_TEXT_SC.style.visibility="hidden";
			document.body.appendChild(SYS_TEXT_SC);
		}//创建文本读取容器
		var SYS_TEXT=document.querySelector("SYS_TEXT_SCREEN");
		SYS_TEXT.style.width=this.screenX+"px";
		SYS_TEXT.style.fontSize=this.S.fontSize+"px";
		var ramLength=Math.round((this.screenX/this.S.fontSize)*(this.screenY/this.S.fontSize));
		ramLength=ramLength>1500?1500:ramLength;
		var data=this.textData;
		var ramLength=data.length>ramLength?ramLength:data.length;//每页大约的文字长度
		if(direction=="next"){
			SYS_TEXT.innerText=data.substr(this.ramPoint,ramLength);
			while(SYS_TEXT.offsetHeight>this.screenY){
				ramLength-=20;
				SYS_TEXT.innerText=data.substr(this.ramPoint,ramLength);
			}
			while(SYS_TEXT.offsetHeightthis.screenY){
				IS_LONG=true;
				ramLength-=20;
				SYS_TEXT.innerText=data.substr(this.ramPoint-ramLength,ramLength);
			}
			if(IS_LONG){
				while(SYS_TEXT.offsetHeightthis.textData.length){

		}else{
			var data=this.getTextData("next");
			this.printT(this.screen,data);
		}
	},
	lastPage:function(){
		/*上一页*/
		if(this.ramPoint<=0){

		}else{
			var data=this.getTextData("last");
			this.printT(this.screen,data);
		}
	},
	diaLog:function(view){
		return showModalDialog(view+".view");
	},
	setColors:function(type){
		var color=this.diaLog("colors");
		if(color==undefined){
			return;
		}
		if(type=="color"){
			this.S.color=color;
			document.querySelector(this.screen).style.color=this.S.color;
			document.querySelector("readerViewBar").style.color=this.S.color;
			document.querySelector("readerViewBar").style.borderBottom="1px solid "+this.S.color;
			document.querySelector("fontColor").style.color=this.S.color;
		}else{
			this.S.background=color;
			document.body.style.background=this.S.background;
			document.querySelector("backgroundColor").style.color=this.S.background;
		}
	}
};

其次是文件读写模块ioMod.js

/*文件读写模块*/
this.ioMod={
	getBookList:function(folder){
		var data=[];
		/*取得书籍列表*/
		var fso=new ActiveXObject("Scripting.FileSystemObject");
		var f=fso.GetFolder(folder);
		var fc=new Enumerator(f.files);
		var books=/(.txt|.pdf)/i;
		for (; !fc.atEnd(); fc.moveNext())
		{
			if(books.test(fc.item())==true){
				data.push({url:""+fc.item(),name:fc.item().name});
			}
		}
		return data;
	},
	getFolderList:function(folder){
		/*取得文件夹列表*/
		var data=[];
		var fso=new ActiveXObject("Scripting.FileSystemObject");
		var f=fso.GetFolder(folder);
		var fc=new Enumerator(f.SubFolders);
		var str="\r\n";
		for (; !fc.atEnd(); fc.moveNext())
		{
			data.push({url:""+fc.item(),name:fc.item().name});
		}
		return data;
	},
	openFile:function(url){
		/*读取文件流*/
		var fso=new ActiveXObject("Scripting.FileSystemObject");
		var fl=fso.OpenTextFile(url,1);
		doc=fl.ReadAll();
		fl.Close();
		return doc;
	},
	getSetting:function(){
		/*读取配置*/
		var fso=new ActiveXObject("Scripting.FileSystemObject");
		var fl=fso.OpenTextFile("setting.json",1);
		data=fl.ReadAll();
		data=JSON.parse(data);
		fl.Close();
		return data;
	},
	setSetting:function(data){
		/*写入配置*/
		data=JSON.stringify(data);
		var fso=new ActiveXObject("Scripting.FileSystemObject");
		var tf=fso.CreateTextFile("setting.json",true);
		tf.Write(data);
		tf.Close();
	},
	write:function(data,fileName){
		/*写入配置*/
		var fso=new ActiveXObject("Scripting.FileSystemObject");
		var tf=fso.CreateTextFile(fileName,true);
		tf.Write(data);
		tf.Close();
	},
}

然后是主视图main.hta




文本阅读器v1.0




	
		
			最近阅读
		
		
		
			测试文件.pdf
		
		
			浏览文件
		
		

		
	
	
		进度:  
		文件->
	
	
		
	
	
		
			主题设置
		
		
			字体颜色:
背景颜色:
字体大小:24px
字体设置:宋体
系统设置 添加书签 书签管理

然后是颜色选择器视图colors.view




文本阅读器【颜色选择控件】


基础的功能已完成,剩下的只是添加功能了。暂时没添加对pdf的支持,可以使用“xpdf-chinese-simplified”库将pdf转换为txt在进行读取,还可以添加对SAPI的支持,使软件具有朗读电子书的功能。

你可能感兴趣的:(桌面应用开发)