• CKEditor4多个span标签不合并的问题


    编辑器编辑完成之后的html源码如下

    由于项目要求,我们考虑在php端解决这个问题,采用dom的方式,也考虑过正则匹配,但是考虑的意外情况太多,代码可读性也不高

    下面是解决的一个demo源码

     1 <?php
     2 /**
     3  * 处理返回界面中多个span不合并的问题
     4  *
     5  * @param $html
     6  *
     7  * @return string
     8  * 1.查找全部的span 节点
     9  * 2.找出节点中需要处理的span节点(只有为span标签的父亲,无兄无弟无子)
    10  * 3.遍历节点并处理
    11  */
    12 function handleHtmlManySpan($html)
    13 {
    14     $dom=new DOMDocument();
    15     $dom->loadHTML($html);
    16     $nodes = $dom->getElementsByTagName('span');
    17     $waitingNodes = [];
    18     foreach ($nodes as $node) {
    19         if (isMinimalSpanNode($node)) {
    20             $waitingNodes[] = $node;
    21         }
    22     }
    23     foreach ($waitingNodes as $node) {
    24         handleMinimalSpanNode($node);
    25     }
    26     $html = $dom->saveHTML();
    27     preg_match('/<body>(.*?)</body>/', $html, $matches);
    28     return isset($matches[1])?$matches[1]:'';
    29 }
    30 
    31 /**
    32  * 判断html的dom节点是否是只有span的父亲,无兄无弟无子
    33  * @param $node
    34  *
    35  * @return bool
    36  */
    37 function isMinimalSpanNode($node)
    38 {
    39     return $node->parentNode->nodeName=='span' && $node->nextSibling===null&&$node->previousSibling===null && $node->hasChildNodes() && count($node->childNodes)==1 && $node->childNodes[0]->nodeType==XML_TEXT_NODE;
    40 }
    41 
    42 /**
    43  * 将符合条件的span节点删除,并将样式及内容交还给父亲,并且递归调用
    44  * @param $node
    45  */
    46 function handleMinimalSpanNode($node)
    47 {
    48     $nodeStyle = $node->getAttribute('style');
    49     $nodeValue = $node->nodeValue;
    50     $parentNode = $node->parentNode;
    51     $parentNode->setAttribute('style', $parentNode->getAttribute('style').$nodeStyle);
    52     $parentNode->removeChild($node);
    53     $parentNode->nodeValue = $nodeValue;
    54     if (isMinimalSpanNode($parentNode)) {
    55         handleMinimalSpanNode($parentNode);
    56     }
    57 }
    58 
    59 $str = '<p><span style="color:red;"><span></span><strong><span style="font-weight:bold;"><span style="font-style: italic;"><span style="font-size:12px;">ceshi</span></span></span></strong></span></p><p><span style="color:red;"><span></span><strong><span style="font-weight:bold;"><span style="font-style: italic;"><span style="font-size:12px;">ceshi</span></span></span></strong></span></p>';
    60 echo handleHtmlManySpan($str);

    正则替换的方式解决的不够彻底,下面是代码,也可能是我的正则技术不够优秀,欢迎留言

        /**
         * 解决返回到主页的html显示有多个span的问题
         * 将返回的html中的多个span改为1个,将多个span的样式集中为一个
         */
        function replaceSpanReg($htmlText)
        {
            $pattern = "/<span style="(.*?)">/";
            $pregNum = preg_match_all($pattern,$htmlText,$matches);
            if($pregNum>1){
                $style = implode("",$matches[1]);
                $strLeftBefore = implode("",$matches[0]);
                $strRightBefore = '';
                for($i=1;$i<=$pregNum;$i++){
                    $strRightBefore .= '</span>';
                }
                $strLeftNow = '<span style="'.$style.'">';
                $htmlText = str_replace('
    ','',$htmlText);
                $htmlText = str_replace($strLeftBefore,$strLeftNow,$htmlText);
                $htmlText = str_replace($strRightBefore,'</span>',$htmlText);
            }
            return $htmlText;
        }

    最上面的代码只能解决最内层的span标签的逐渐删除,下面代码是优化版本,个人感觉更佳

       /**
         * 处理返回界面中多个span不合并的问题
         *
         * @param $html
         *
         * @return string
         * 1.查找全部的span 节点
         * 2.找出节点中需要处理的span节点(只有为span标签的父亲,无兄无弟无子)
         * 3.遍历节点并处理
         */
        function handleHtmlManySpan($html)
        {
            $dom=new DOMDocument();
            $dom->loadHTML($html);
            $nodes = $dom->getElementsByTagName('span');
            $waitingNodes = [];
            foreach ($nodes as $node) {
                if (isWaitingHandleSpanNode($node)) {
                    $waitingNodes[] = $node;
                }
            }
            foreach ($waitingNodes as $node) {
                handleSpanNode($node);
            }
            $html = $dom->saveHTML();
            preg_match('/<body>(.*?)</body>/', $html, $matches);
            return isset($matches[1])?$matches[1]:'';
        }
    
        /**
         * 判断当前的span标签是否需要处理
         * 1.如果父标签是span而且没有兄弟标签即处理 ,并且只有一个子元素的时候不是span,也可以有多个子元素
         * @param $node
         *
         * @return bool
         */
        function isWaitingHandleSpanNode($node)
        {
            $isWaiting = false;
            //父标签为span且无兄无弟
            if($node->parentNode->nodeName=='span' && $node->nextSibling===null&&$node->previousSibling===null)
            {
                if(count($node->childNodes)!=1){
                    $isWaiting = true;
                }else if(count($node->childNodes)==1 && $node->childNodes[0]->nodeName!='span'){
                    $isWaiting = true;
                }
            }
            return $isWaiting;
            //return $node->parentNode->nodeName=='span' && $node->nextSibling===null&&$node->previousSibling===null;
        }
        /**
         * 将符合条件的span节点删除,并将样式及内容交还给父亲,并且递归调用
         * @param $node
         */
        function handleSpanNode($node)
        {
            $nodeStyle = $node->getAttribute('style');
            $parentNode = $node->parentNode;
            $parentNode->setAttribute('style', $parentNode->getAttribute('style').';'.$nodeStyle);
            if(count($node->childNodes)>0){
                foreach($node->childNodes as $child)
                {
                    $parentNode->appendChild($child);
                }
            }
            $parentNode->removeChild($node);
    
            if (isWaitingHandleSpanNode($parentNode)) {
                handleSpanNode($parentNode);
            }
        }

    $str = '<p><span style="color:red"><span style="font-size:12px"><strong><span style="backgrount:red"><span>ces</span></span></strong></span></span></p>';
      echo
    handleHtmlManySpan($str);
     
  • 相关阅读:
    旋转卡壳(1)求凸包(点集)直径 poj 2187
    求解平面最近点对的问题
    java中的内部类初识
    java中的多重继承
    ObjectiveC中的Protocols
    Mac中配置java的src.jar
    Mac OS X Lion无线网络问题
    Xcode中修改默认文件头部注释
    全文索引查询和like查询对比
    获取Repeater选中行索引
  • 原文地址:https://www.cnblogs.com/bafeiyu/p/12441092.html
Copyright © 2020-2023  润新知