您的位置 首页 php

用PHP操作DOM (二)

上次我们完成了cssitem的工作,接下来我们来完成CSS_Class的设计工作,思路很简单,就是完成样式类的功能,有个问题我一直搞不明白,头条什么不支持markdown,这简直就是反人类呀。详细说明代码中我已经做了注释。

/**

* CSS_class类

* 测试文件:test.class_speedx_style_class.php

* @$className: 样式名,为空时,则创建匿名样式

* @$classItem: CSS属性对象或样式对象,对于特定类,其内部可以包含样式类。

* 本类是创建CSS样式的关键类,根据CSS类特性,可分为以下几类:

* SPEEDX_CLASS_ANONYMOUS:匿名类,即没有类名称的CSS类

* SPEEDX_CLASS_IMPORT:@import类

* SPEEDX_CLASS_ charset :@charset类

* SPEEDX_CLASS_MEDIA:@media类

* SPEEDX_CLASS_FONTFACE:@font-face类

* SPEEDX_CLASS_PAGE:@page类

* SPEEDX_CLASS_KEYFRAMES:@keyframes类

* SPEEDX_CLASS_SUPPORTS:@supports类

* SPEEDX_CLASS_STANDARD:标准类

* 其方法:append()可以直接输入一个 样式属性|类|数组|直接创建属性类的参数。

* 本方法可根据输入的参数类型做自动判断。

*/

class speedx_css_class{

private $className = “”;

private $attrList = [];

private $type = SPEEDX_CLASS_ANONYMOUS;

public $browser = SPEEDX_STYLE_DEFAULT;

//public $level = 0;

private function _setName_($className){

if(is_string($className)){

$className = trim (rtrim(trim($className),”;”));

if(empty($className)){

$this->className = “”;

}else{

$this->className = $className;

}

}else{

$this->className = “”;

}

if(!empty($this->className)){

if(strpos($this->className,’@import’) === 0){$this->type = SPEEDX_CLASS_IMPORT;}

elseif(strpos($this->className,’@charset’) === 0){$this->type = SPEEDX_CLASS_CHARSET;}

elseif(strpos($this->className,’@media’) === 0){$this->type = SPEEDX_CLASS_MEDIA;}

elseif(strpos($this->className,’@font-face’) === 0){$this->type = SPEEDX_CLASS_FONTFACE;}

elseif(strpos($this->className,’@page’) === 0){$this->type = SPEEDX_CLASS_PAGE;}

elseif(strpos($this->className,’@keyframes’) === 0){$this->type = SPEEDX_CLASS_KEYFRAMES;}

elseif(strpos($this->className,’@supports’) === 0){$this->type = SPEEDX_CLASS_SUPPORTS;}

else{$this->type = SPEEDX_CLASS_STANDARD;}

}else{

$this->className = “”;

$this->type = SPEEDX_CLASS_ANONYMOUS;

}

}

private function _addItem_($item node ){

if(is_css_item($itemNode)){

$cssItem = $this->attrList;

$cssItem = array_filter($cssItem,function($_item)use($itemNode){

if(is_css_class($_item)){

return true;

}elseif(is_css_item($_item)){

if($_item->name === $itemNode->name){

return false;

}else{

return true;

}

}else{

return false;

}

});

$cssItem[] = $itemNode;

$this->attrList = $cssItem;

}

}

private function _addClass_($classNode){

if(is_css_class($classNode)){

$classList = $this->attrList;

$classList = array_filter($classList,function($_classNode)use($classNode){

if(is_css_class($_classNode)){

if($_classNode->name === $classNode->name){

return false;

}else{

return true;

}

}elseif(is_css_item($_classNode)){

return true;

}else{

return false;

}

});

$classList[] = $classNode;

$this->attrList = $classList;

}

}

private function _analysis_(){

$classString = “”;

if($this->type === SPEEDX_CLASS_ANONYMOUS && empty($this->attrList))return $classString;

if(in_array($this->type,[SPEEDX_CLASS_IMPORT,SPEEDX_CLASS_CHARSET]))return $this->className.”;”;

//if(empty($this->attrList))return $classString;

$type = [SPEEDX_CLASS_ANONYMOUS,SPEEDX_CLASS_MEDIA,SPEEDX_CLASS_FONTFACE,SPEEDX_CLASS_PAGE,SPEEDX_CLASS_SUPPORTS,SPEEDX_CLASS_STANDARD];

$attrList = “”;

if(in_array($this->type,$type)){

foreach($this->attrList as &$attr){

if(is_css_item($attr)){

$attr->browser = $this->browser;

}

}

$attrList = implode(“”,$this->attrList);

$classString = [$this->className,”{“,$attrList,”}”];

$classString = implode(“”,$classString);

return $classString;

}elseif($this->type === SPEEDX_CLASS_KEYFRAMES){

//$attrList = implode(“”,$this->attrList);

$tpl = [“-moz-“,”-webkit-“,””];

$string = “”;

foreach($tpl as $val){

if($val == “-moz-“){

foreach($this->attrList as &$attr){

$attr->browser = SPEEDX_STYLE_MOZ;

}

}else if($val == “-webkit-“){

foreach($this->attrList as &$attr){

$attr->browser = SPEEDX_STYLE_WEBKIT;

}

}else{

foreach($this->attrList as &$attr){

$attr->browser = SPEEDX_STYLE_DEFAULT;

}

//$this->itemBrowser = SPEEDX_STYLE_DEFAULT;

}

$attrList = implode(“”,$this->attrList);

$strTpl = [‘@’.$val.ltrim($this->className,’@’),”{“,$attrList,”}”];

$string .= implode(“”,$strTpl);

}

$classString = $string;

return $classString;

}

}

public function __construct($className = “”){

$this->_setName_($className);

}

/**

* 向speedx_class类中添加CSS属性:

* $attrNode参数可以为改下几种:

* 属性类:即参数为speedx_style_item对象

* 样式类:即speedx_class类

* 数组:由speedx_class对象和speedx_style_item对象组成的数组

*/

public function append($attrNode = null){

$importType = [SPEEDX_CLASS_IMPORT,SPEEDX_CLASS_CHARSET];

$standardType = [SPEEDX_CLASS_ANONYMOUS,SPEEDX_CLASS_PAGE,SPEEDX_CLASS_FONTFACE,SPEEDX_CLASS_STANDARD];

$keyframesType = [SPEEDX_CLASS_SUPPORTS,SPEEDX_CLASS_MEDIA,SPEEDX_CLASS_KEYFRAMES];

if(is_null($attrNode))return $this;

if(in_array($this->type,$importType))return $this;

if(is_css_item($attrNode)){

$this->_addItem_($attrNode);

}else if(is_css_class($attrNode)){

if(in_array($this->type,$standardType)){

$_addItem = $attrNode;

if(is_css_class($attrNode)){

$_addItem = $attrNode->value;

foreach($_addItem as $_item){

$this->_addItem_($_item);

}

}else{

$this->_addItem_($_addItem);

}

}else if(in_array($this->type,$keyframesType)){

if(is_css_item($attrNode)){

$this->_addItem_($attrNode);

}else if(is_css_class($attrNode)){

$this->_addClass_($attrNode);

}

}

}else if(is_array($attrNode)){

foreach($attrNode as $node){

$this->append($node);

}

}else{

return $this;

}

return $this;

}

/**

* 移除指定的属性|样式类对象

*/

public function remove($attrName = null){

if(empty(trim($attrName.””))){

$this->attrList = [];

return $this;

}

$attrName = strtolower(trim($attrName));

$this->attrList = array_filter($this->attrList,function($_node)use($attrName){

return $_node->name !== $attrName;

});

return $this;

}

/**

* 判断类中是否存在指定的属性对象;

*/

public function exists($attrName){

if(empty($this->attrList))return false;

$attrName = trim($attrName.””);

if(empty($attrName)) return false;

foreach($this->attrList as $item){

if(is_css_item($item)){

if($item->name === $attrName) return true;

}

}

return false;

}

public function __get($name){

if($name === “name”){

return $this->className;

}elseif($name === “value”){

return $this->attrList;

}elseif($name === “type”){

return $this->type;

}elseif(!empty(trim($name.””))){

$name = strtolower(trim($name));

foreach($this->attrList as $val){

if($val->name === $name){

return $val;

}

}

}else{

return null;

}

}

public function __toString(){

return $this->_analysis_();

}

}

下面是相关的工具构造函数,方便使用:

/**

* 创建CSS类节点

* @name:类名,为空时创建匿名样式类

*/

function create_css_class($name=””){

return new speedx_css_class($name);

}

/**

* 从给定的文本创建样式类,返回由样式类组成的数组。其中不包含匿名类,转化失败时,返回null。

* @$string:要转化的字符表达式

*/

function create_css_classes_from_string($string){

$string = trim($string);

$preg = [];

$preg[] = ‘/\/\*[^\/]*\*\//’;//删除注释

$preg[] = “/(\/\*[^\/]*\*\/)|(-webkit-)|(-moz-)|(-ms-)|(-o-)/i”;//删除浏览器前缀

$string = trim(preg_replace($preg,””,$string));

$class = [];

$preg = “/(@[^\{\}]+;)|([@\-#\.\s*\w%]+)\s*\{([^\{\}]+)\}/i”;

$index = 0;

while(preg_match($preg,$string,$matches,PREG_OFFSET_CAPTURE)){

$classFlag = “<cssFlag_$index>”;

$classKey = “cssFlag_$index”;

$fullClass = $matches[0][0];

$pos = $matches[0][1];

$length = strlen($fullClass);

$class[$classKey] = trim($fullClass);

$string = trim(substr_replace($string,$classFlag.”;”,$pos,$length));

$index++;

$className = “”;

$classBody = “”;

if(isset($matches[1][0])) $className .= trim($matches[1][0]);

if(isset($matches[2][0])) $className .= trim($matches[2][0]);

if(isset($matches[3][0])) $classBody .= trim($matches[3][0]);

$new_css_class = create_css_class($className);

if(empty($new_css_class.””)){

$class[$classKey] = null;

}else{

if(!empty($classBody)){

$classBody = explode(“;”,$classBody);

$classBody = array_filter($classBody,function($item){return !empty(trim($item));});

$classBody = array_map(function($item){return trim($item);},$classBody);

$classBody = array_unique($classBody);

foreach($classBody as $_body){

$_body = trim(ltrim($_body,”<“));

$_body = trim(rtrim($_body,”>”));

if(array_key_exists($_body,$class)){

if(is_css_class($class[$_body])){

$new_css_class->append($class[$_body]);

}

$class[$_body] = null;

}else{

$new_item = create_css_item_from_string($_body);

if(!is_null($new_item)){

$new_css_class->append($new_item);

}

}

}

}

$class[$classKey] = $new_css_class;

}

}

$class = array_filter($class,function($_class){return is_css_class($_class);});

//以下为去重

$classNames = [];

$_classes = [];

foreach($class as $_class){

$class_name = $_class->name;

if(!in_array($class_name,$classNames)){

$classNames[] = $class_name;

$_classes[] = $_class;

}

}

$class = $_classes;

unset($_classes); unset($classNames);

if(empty($class)) return null;

return $class;

}

/**

* 从字符串中解析DOM文档

*/

function load_nodes_fromString($input = “”){

$input = $input . “”;

if(empty(trim($input.””)))return null;

$DOMNODE = null;

$preg = “/\<\s*(?:!DOCTYPE|!–|\\\$*_var_|img|br|meta|base|embed|link|track|input|keygen)[^\<\>]*\>/i”;

$domNodes = [];

$index = 0;

$input = preg_replace_callback($preg,function($matches)use(&$index,&$domNodes){

if(isset($matches)){

if(isset($matches)){

$node = create_node($matches[0]);

if($node->nodeType !== SPEEDX_NODE_NULL){

$domNodes[“singleNode_$index”] = $node;

$replace = “{{singleNode_$index}}”;

$index++;

return $replace;

}

}

}

},$input);

$iterationFlag = true;

$SPEEDX_NODE_TYPE = $GLOBALS[“SPEEDX_NODE_TYPE”];

$SPEEDX_NODE_TYPE = $SPEEDX_NODE_TYPE[SPEEDX_NODE_STANDARD];

$SPEEDX_NODE_TYPE[] = “style”;

$SPEEDX_NODE_TYPE[] = “script”;

$SPEEDX_NODE_TYPE = trim(implode(“|”,$SPEEDX_NODE_TYPE));

$preg = ‘/(\<\s*(‘ . $SPEEDX_NODE_TYPE . ‘)\s*[^\<\>]*\>)([^\<\>]*)\<\s*\/\2\s*\>/i’;

while($iterationFlag){

$iterationFlag = false;

$input = preg_replace_callback($preg,function($matches)use(&$index,&$domNodes,&$iterationFlag){

$iterationFlag = true;

$node = create_node($matches[1]);

if($node->nodeType === SPEEDX_NODE_STANDARD){

$preg = ‘/(\{\{\w+\d+\}\})/’;

$str = isset($matches[3]) ? trim($matches[3]) : “”;

if(!empty($str)){

$t = preg_split($preg,$str,null,PREG_SPLIT_NO_EMPTY+PREG_SPLIT_DELIM_CAPTURE);

foreach($t as &$v){

$v = trim($v);

$vk = trim($v,”{}”);

if(isset($domNodes[$vk])){

$tn = $domNodes[$vk];

$v = $tn;

$domNodes[$vk] = null;

$domNodes = array_filter($domNodes,function($val){return !is_null($val);});

}else{

$v = create_nodeText($v);

}

}

$node->append($t);

}

}elseif($node->nodeType === SPEEDX_NODE_STYLE){

if(!empty($matches[3])){

$styleClasses = load_class_fromString($matches[3]);

$node->append($styleClasses);

}

}elseif($node->nodeType === SPEEDX_NODE_SCRIPT){

if(!empty($matches[3])){

$minjs = create_jsMin($matches[3]);

$node->append($minjs);

}

}

$domNodes[“standardNode_$index”] = $node;

$replace = “{{standardNode_$index}}”;

$index++;

return $replace;

},$input);

}

$preg = ‘/(\{\{\w+\d+\}\})/’;

$str = $input;

if(!empty($str)){

$t = preg_split($preg,$str,null,PREG_SPLIT_NO_EMPTY+PREG_SPLIT_DELIM_CAPTURE);

foreach($t as &$v){

$v = trim($v);

$vk = trim($v,”{}”);

if(isset($domNodes[$vk])){

$v = $domNodes[$vk];

}else{

$v = create_nodeText($v);

}

}

$DOMNODE = $t;

}

return $DOMNODE;

}

下面我们来测试一下,不要忘记这个代码一定要和上次的代码结合起来用哦,不然会报错的,测试代码如下:

//创建标准样式类

$cssItem1 = create_css_item(“width”,”100px”);

$cssItem2 = create_css_item(“display”,”inline-box”);

$class_standard_div = create_css_class(“.div”)->append($cssItem1)->append($cssItem2);

echo $class_standard_div . “<hr/>”;

//获取成员属性对象的值。

echo $class_standard_div->width->value . “<hr/>”;

//创建import样式类

$class_import = create_css_class(“@import url(example.css) screen and (min-width:800px);”);

echo $class_import . “<hr/>”;

//创建charset样式类

$class_charset = create_css_class(‘@charset “utf-8″‘);

echo $class_charset . “<hr/>”;

//创建supports样式类

$supports_item = create_css_class(“.demo”)->append(create_css_item(“box-shadow”,”2px 2px 0 rgba(0, 0, 0, .3)”));

$class_supports = create_css_class(“@supports (box-shadow: 2px 2px) or (-moz-box-shadow: 2px 2px) or (-webkit-box-shadow: 2px 2px)”)->append($supports_item);

echo $class_supports . “<hr/>”;

//创建keyframe样式类

$keyframe_item1 = create_css_class(“0%”)->append(create_css_item(“transform”,”translate(0, 0)”));

$keyframe_item2 = create_css_class(“20%”)->append(create_css_item(“transform”,”translate(20px, 20px)”));

$keyframe_item3 = create_css_class(“40%”)->append(create_css_item(“transform”,”translate(40px, 0)”));

$keyframe_item4 = create_css_class(“60%”)->append(create_css_item(“transform”,”translate(60px, 20px)”));

$keyframe_item5 = create_css_class(“80%”)->append(create_css_item(“transform”,”translate(80px, 0)”));

$keyframe_item6 = create_css_class(“100%”)->append(create_css_item(“transform”,”translate(100px, 20px)”));

$class_keyframe = create_css_class(“@keyframes testanimations”)->append($keyframe_item1)

->append($keyframe_item2)->append($keyframe_item3)->append($keyframe_item4)->append($keyframe_item5)->append($keyframe_item6);

echo $class_keyframe . “<hr/>”;

$item = create_css_item(“width”,”100px;”);

$anyclass = create_css_class()->append($item);

echo $anyclass . “<br/>”;

测试结果如下:

.div{width:100px;-ms-display:inline-box;-webkit-display:-webkit-inline-box;-moz-display:-moz-inline-box;display:inline-box;}
100px
@import url(example.css) screen and (min-width:800px);
@charset "utf-8";
@supports (box-shadow: 2px 2px) or (-moz-box-shadow: 2px 2px) or (-webkit-box-shadow: 2px 2px){.demo{-webkit-box-shadow:2px 2px 0 rgba(0,0,0,.3);-moz-box-shadow:2px 2px 0 rgba(0,0,0,.3);box-shadow:2px 2px 0 rgba(0,0,0,.3);}}
@-moz-keyframes testanimations{0%{-moz-transform:translate(0,0);transform:translate(0,0);}20%{-moz-transform:translate(20px,20px);transform:translate(20px,20px);}40%{-moz-transform:translate(40px,0);transform:translate(40px,0);}60%{-moz-transform:translate(60px,20px);transform:translate(60px,20px);}80%{-moz-transform:translate(80px,0);transform:translate(80px,0);}100%{-moz-transform:translate(100px,20px);transform:translate(100px,20px);}}@-webkit-keyframes testanimations{0%{-webkit-transform:translate(0,0);transform:translate(0,0);}20%{-webkit-transform:translate(20px,20px);transform:translate(20px,20px);}40%{-webkit-transform:translate(40px,0);transform:translate(40px,0);}60%{-webkit-transform:translate(60px,20px);transform:translate(60px,20px);}80%{-webkit-transform:translate(80px,0);transform:translate(80px,0);}100%{-webkit-transform:translate(100px,20px);transform:translate(100px,20px);}}@keyframes testanimations{0%{-ms-transform:translate(0,0);-webkit-transform:translate(0,0);-moz-transform:translate(0,0);transform:translate(0,0);}20%{-ms-transform:translate(20px,20px);-webkit-transform:translate(20px,20px);-moz-transform:translate(20px,20px);transform:translate(20px,20px);}40%{-ms-transform:translate(40px,0);-webkit-transform:translate(40px,0);-moz-transform:translate(40px,0);transform:translate(40px,0);}60%{-ms-transform:translate(60px,20px);-webkit-transform:translate(60px,20px);-moz-transform:translate(60px,20px);transform:translate(60px,20px);}80%{-ms-transform:translate(80px,0);-webkit-transform:translate(80px,0);-moz-transform:translate(80px,0);transform:translate(80px,0);}100%{-ms-transform:translate(100px,20px);-webkit-transform:translate(100px,20px);-moz-transform:translate(100px,20px);transform:translate(100px,20px);}}
{width:100px;}
 

是不是很完美,是的,相当完美,符合我的预期。

到这里CSS部分就结束了,后面是DOM的相关设计。待续

文章来源:智云一二三科技

文章标题:用PHP操作DOM (二)

文章地址:https://www.zhihuclub.com/79324.shtml

关于作者: 智云科技

热门文章

网站地图