在初次使用ckEditor文本编辑器过程中发现,其中的“分页”功能(编辑器中的分页按钮)实际的作用只是在文中产生一个带样式的div,并没有提供别的内容。形式如下:
<div style="page-break-after: always"> <span style="display: none;"> </span></div>
这也许只是用于打印时的分页,要实现浏览的分页可能还没这个能力。于是想在此上设计出一个功能来分页,用户只用在编辑器上选择分页即可。通过观察包含的<span>带有默认隐藏样式,于是最初想到是否在此做文章,但又想到了用javascript的字符串操作非常方便,于是想选用javascript来设计一个解决方法。思想是:搜索并记录文中包含所有此标签的位置(<div style="page-break-after: always">),按索引位置将内容分段截取存入变量,输出换页按钮,通过按钮调用换页函数进行换页。
使用的变量为:
var content=new Object; var context="";//HTML文本内容 var pgindex=[];//存储分页位置的数组 var cont=[];//存储分段内容 var pagesel="";//生成分页标签时用 var contpg=0;//页号
详细代码,封装成几个函数,initpg()用于初始化和置空变量并搜索标签位置:
function initpg(){ //置空变量 contpg=0; pgindex.splice(0,pgindex.length); pgindex[0]=0; cont.splice(0,cont.length); pagesel=""; //获取节点HTML文本内容,搜索所有分页标签出现位置 content=document.getElementById("nc_con"); context=content.innerHTML; var i=0; var j=1; var tmpp=0; while(tmpp=context.indexOf("<div style="page-break-after: always">",i)){ if(tmpp!=-1){ pgindex[j++]=tmpp; i=tmpp+30;//30意为为越过此次搜到标签再开始搜索,实际可精确到此标签的长度 }else{ break; } }
searchpg()依据索引位置将内容分段存入变量并将第一页作为初始内容显示
searchpg(){ if(pgindex.length>1){ for(var i=0;i<pgindex.length;i++) { cont[i]=context.substring(pgindex[i],pgindex[i+1]); } pagese(); content.innerHTML=cont[0]; document.getElementById("nc_page").innerHTML=pagesel;//换页使用的按钮内容输出在id=nc_page元素下 }else pagese(); document.getElementById("nc_page").innerHTML=pagesel; }
pagese()依据当前所在页码确定所需的控制换页按钮选项,即pagesel的内容,pagesel在searchpg()中被使用。
function pagese(){ if(cont.length>0){ if(contpg==0){ pagesel="文章共"+cont.length+"页 当前第"+(contpg+1)+"页<br/><hr />首 页 上一页 <a href='#' onclick='nextpa()'>下一页</a> <a href='#' onclick='endpa()'>末 页</a>"; }else if(contpg!=0&&contpg<cont.length-1){ pagesel="文章共"+cont.length+"页 当前第"+(contpg+1)+"页<br/><hr /><a href='#' onclick='firstpa()'>首 页</a> <a href='#' onclick='prepa()'>上一页</a> <a href='#' onclick='nextpa()'>下一页</a> <a href='#' onclick='endpa()'>末 页</a>"; }else if(contpg==cont.length-1){ pagesel="文章共"+cont.length+"页 当前第"+(contpg+1)+"页<br/><hr /><a href='#' onclick='firstpa()'>首 页</a> <a href='#' onclick='prepa()'>上一页</a> 下一页 末 页"; } }else { pagesel="文章共1页 当前第1页<br/><hr />"; } }
按钮触发的换页动作依据nextpa()、prepa()、firstpa()、endpa()几个函数产生
function nextpa(){ contpg++; pagese(); content.innerHTML=cont[contpg]; document.getElementById("nc_page").innerHTML=pagesel; } function prepa(){ contpg--; pagese(); content.innerHTML=cont[contpg]; document.getElementById("nc_page").innerHTML=pagesel; } function firstpa(){ contpg=0; pagese(); content.innerHTML=cont[contpg]; document.getElementById("nc_page").innerHTML=pagesel; } function endpa(){ contpg=cont.length-1; pagese(); content.innerHTML=cont[contpg]; document.getElementById("nc_page").innerHTML=pagesel; }
这样大体上的内容就完成了,调用时在正文内容的下方(或放入window.onload中)先调用initpg()初始化,再使用searchpg()确定页内容及换页的按钮即可。
<div id="nc_con"> //内容 </div> <div id="nc_page"> //分页操作按钮 </div> <script type="text/javascript"> initpg(); searchpg(); </script>
在实际使用中发现,chrome和FF测试均通过,IE却不行,仔细试验发现,在不同浏览器生成的标签是不同的(部分IE下为大写字母,并且存在有;和没有;的差异)
部分IE:
<DIV style="PAGE-BREAK-AFTER: always;"> <SPAN style="DISPLAY: none;"> </SPAN></DIV>
Chrome、FF:
<div style="page-break-after: always"> <span style="display: none;"> </span></div>
于是将关键字缩小到不包含分号并在头部加入浏览器判断:
var Sys = {}; var ua = navigator.userAgent.toLowerCase(); if (window.ActiveXObject) Sys.ie = ua.match(/msie ([\d.]+)/)[1]
修改initpg()为:
function initpg(){ contpg=0; pgindex.splice(0,pgindex.length); pgindex[0]=0; cont.splice(0,cont.length); pagesel=""; content=document.getElementById("content"); context=content.innerHTML; if(Sys.ie){ var i=0; var j=1; var tmpp=0; while(tmpp=context.indexOf("<DIV style=\"PAGE-BREAK-AFTER: always",i)){ if(tmpp!=-1){ pgindex[j++]=tmpp; i=tmpp+30; }else{ break; } } }else{ var i=0; var j=1; var tmpp=0; while(tmpp=context.indexOf("<div style=\"page-break-after: always",i)){ if(tmpp!=-1){ pgindex[j++]=tmpp; i=tmpp+30; }else{ break; } } }
另外这样的方法是能够实现了无刷新换页,但需要考虑一个因素,就是js的执行问题——如果DOM没有准备好。比如网络速度影响页面元素加载不完全,使js不执行的问题(甚至如果将代码放入window.onload中)。另外,如果有使用AJAX来异步加载内容的话,需要考虑函数的重新触发。比如可将此分页函数加入到AJAX的回调中,使其置空变量并重新执行。因此这只是没有参考其他资料情况下作出的解决方案,如果将这功能实现到服务器脚本上,应该会达到其他的效果。有机会应该考虑用PHP实现之。