文章详情按字数自动分页功能

在我们公司建站系统中,前台文章详情模块,有个功能是文章详情内容自动按照字数做分页(比如:每1000字做分页),对于某些长文章来说可以提高加载速度。

由于文章详情内容是用富文本内容,包含html代码,所以不能直接做文字切分,需要对html进行解析后处理,比较复杂,这块我们以前的实现是使用正则自己去解析文字然后做分页,一旦出现表格,段落,div等组合标签就可能导致文章结构错乱,所以在以前的实现里,我们只好一刀切,判断如果有部分html标签的文章,就不进行分页,就导致这个功能时灵时不灵,形同虚设。

这一次我决定重新实现这个功能,首先,我决定不自己解析html代码,而使用第三方html解析类库,于是我在网上找到了simplehtmldom这个类库

http://sourceforge.net/projects/simplehtmldom/

这个类库可以将html文本转换成DOM Node树,所有的文本都在Text Node里,只需要计算Text Node中文字的数量,可以避免把标签文字计算为内容文字数量,于是整个流程简化为如下四步:

1. 遍历整个DOM数,遇到Text Node就计算字数,并判断该Node所在的页数。

2. 如果这个Node在需要显示的页面内,保留这个Node以及他所有的父节点,反之删除节点,

3. 在遍历结束后可以获取文章详情的总页数

4. 将保留下的DOM树元素重新转成html代码并显示

下面是文章分页器 php代码 :

​
<?php
require_once('simple_html_dom.php');
class ArticleSpliter{
    private $count_text_num=0;
    private $dom_cur_page=1;
    public $count_per_page=0;
    public $show_page=1;

    public function split($mybody){
        $this->count_text_num=0;
        $this->dom_cur_page=1;
        $thedom=str_get_html($mybody);
        $root=$thedom->root;
        $this->parseDomTree($root);
        return $thedom->root->innertext();
    }

    public function getTotalPage(){
        return $this->dom_cur_page;
    }

    private function parseDomTree($dom,$isinsepcialel=false){
        if(empty($dom->nodes)) return;
        if(!$isinsepcialel && $this->count_text_num>=$this->count_per_page){
                  $this->dom_cur_page+=1;
                  $this->count_text_num=0;
        }
        $domtag=strtolower($dom->tag);
        if($domtag=='table' || $domtag=='ul' || $domtag=='ol'){
            $isinsepcialel=true;
        }
        foreach($dom->nodes as $child){ 
          if($this->dom_cur_page!=$this->show_page) $child->is_del=1;
          if($child->tag=='text'){
              $outertext=$child->outertext(false);
              $txtlen=mb_strlen($outertext,'UTF-8');
              $this->count_text_num+=$txtlen;
              if(!$isinsepcialel && $this->count_text_num>=$this->count_per_page){
                  $this->dom_cur_page+=1;
                  $this->count_text_num=0;
              }
          }
           $this->parseDomTree($child,$isinsepcialel);
        }
        if($dom->is_del==1){
            foreach($dom->nodes as $child){ 
                if(!$child->is_del){
                    $dom->is_del=0;
                    break;
                }
            }
        }
    }


}

​

使用代码示例:

扫描二维码关注公众号,回复: 85617 查看本文章
<?php
require_once('articlespliter.php');
$body = <<<EOD
<p>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb</p>
<br/>
<div>aaaaaaaaaaaaaavvvvvvvvvvvvvvvvvv</div>
EOD;

$articlespliter=new ArticleSpliter();
$articlespliter->count_per_page=10;
$articlespliter->show_page=6;
$splitbody=$articlespliter->split($body);
$totalpage=$articlespliter->getTotalPage();

项目的github地址:

https://github.com/James-Ren/articlespliter

所有代码我都打包到zip包里,有需要的可以下载获取

https://pan.baidu.com/s/1rmAS8cZm-0s5dRZo0fjY8A

经过了这番修改后,我们的分页逻辑变得非常的清晰,代码量减少了很多,分页效果也好了很多,线上运行了一段时间,也没有再出现格式错乱的问题了。

猜你喜欢

转载自my.oschina.net/jamesren/blog/1787485