jmasci / html-element
纯HTML元素渲染函数;以及可变HTML元素对象。
Requires (Dev)
- phpunit/phpunit: 4.*
This package is auto-updated.
Last update: 2024-09-16 02:47:38 UTC
README
将HTML渲染库拆分为两个(几乎)非耦合的部分
El类提供了将元素属性转换为HTML的纯方法。您可以单独使用它。
Element类管理元素属性,然后使用El进行渲染。您可以轻松地替换自己的渲染机制。
1. El类
基本用法
use JMasci\HtmlElement\El; echo El::get( 'p', "inner", [ 'class' => 'class-1', ] );
<p class="class-1">...</p>
El::open、定义类/ID的标签以及将类作为列表的演示
echo El::open( 'div.class-1#id', [ 'class' => [ 'class-2', 0 ? 'class-3' : '' ] ] ); echo "inner"; echo El::close( 'div' );
<div id="id" class="class-1 class-2">inner</div>
自闭合标签、将类作为布尔值的字典、JSON编码辅助工具以及仅键属性(例如,必需的)
echo El::open( 'input', [ 'type' => 'number', 'name' => 'number', 'class' => [ 'class-1' => true, 'class-2' => false ], 'min' => 0, 'step' => 1, 'data-json' => El::json_encode_for_html_attr( $some_array_or_object ), 'required' => true, ] );
<input type="number" name="number" class="class-1" min="0" step="1" data-location="{json...}" required />
用户输入/净化/扩展性
El::get() 和 El::open() 将过滤、验证和净化您传入的所有数据(除了内部HTML)。
还有 El::get_strict() 和 El::open_strict(),它不会执行上述任何操作。它期望
- 所有数据都经过净化
- 所有属性都是字符串。
- 标签是有效的标签,且不包含ID或类
您还可以使用用于过滤/验证/净化您的数据的这些方法。您可以使用它们的一个子集,并包装“严格”方法来定义自己的解决方案,以更好地满足您的需求。如果您的数据以您不喜欢的其他方式净化,这可能很有用。扩展该类也是可能的。有关更多信息,请参阅代码;它考虑了可扩展性。
1. Element类
基本用法
use JMasci\HtmlElement\Element; $element = new Element( 'div', [ 'class' => 'container' ], [ new Element( 'p', [], [ "Text" ] ) ] ); echo $element->render();
<div class="container"><p>Text</p></div>
非基本用法。演示了大多数可用方法,但不是全部;请参阅代码以获取更多信息。
use JMasci\HtmlElement\Element; $element = new Element( null ); // set methods normally return $element $element->tag_set( 'div' )->attr_set( 'id', 'main' ); $element->attr_get( 'id' ); # "main" $element->tag_get(); # "div" $element->attr_exists( 'data-test' ); # false $element->attr_set( 'data-test' ); $element->attr_reset( 'data-test' ); $element->attr_exists( 'data-test' ); # true $element->attr_delete( 'data-test' ); $element->attr_exists( 'data-test' ); # false // all methods are potentially variadic. add_class may accept multiple // parameters or arrays. $element->add_class( 'class-1' )->add_class( 'class-2' ); $element->has_class( 'class-1' ); # true $element->remove_class( 'class-2' ); $element->attr_get( 'class' ); # "class-1" // different attributes know how to handle different operations. // the id attribute does not understand "add". The style attribute does. $element->add_style('display: none;'); // there are many ways to do the same thing. This is not a feature, // but a result of the extensibility that is built-in. You should // generally avoid using these methods unless you know what you are doing. // mostly, you'll use them when extending the class to add your own functionality. $element->_compound_attr_add( 'style', 'color: red;'); $element->attr_get_instance( 'style' )->add( 'color: blue;' ); $element->attr_get_instance( 'style' )->_call_dynamic_method( 'add', 'color: green;' ); // this will result in an error, unless you extended the 'id' attribute to define 'has'. // $element->attr_get_instance( 'id' )->_call_dynamic_method( 'has', '...' ); // adding child elements. note: nesting depth of children is unlimited. $element->child_append( new Element('p', [], [ "Paragraph 1" ] )); // stores a string as a child. It is not converted into an Element. $element->child_append( "<p>Paragraph 2</p>"); // prepend a child $element->child_prepend( new Element('p', [], [ "Paragraph 0" ] )); // a "fragment" contains only children. // we created a new element containing 2 children which are the same. // note: $element is not cloned, its a reference. Considering cloning if needed. $fragment = Element::get_fragment_instance( [ $element, $element ] ); $fragment->child_prepend( '<p>Before...</p>' ); echo $fragment->render();
结果如下
<p>Before...</p> <div id="main" class="class-1" style="display: none; color: red; color:blue; color: green;"> <p>Paragraph 0</p> <p>Paragraph 1</p> <p>Paragraph 2</p> </div> <div id="main" class="class-1" style="display: none; color: red; color:blue; color: green;"> <p>Paragraph 0</p> <p>Paragraph 1</p> <p>Paragraph 2</p> </div>
真实世界示例
注意:我不建议您总是使用Element来编写HTML;这样做可能会导致代码混乱。
然而,在某些情况下,缺乏灵活性并不是一个选项。因此,我们可以用一点简单性来换取大量的灵活性。
use JMasci\HtmlElement\Element; // a function that returns Element instances and a function that knows how to render them. // this lets the Element's be modified before rendering. You can use the same idea // in a lot of different ways. function get_the_thing(){ $wrapper = new Element( 'div', [ 'class' => 'wrapper' ] ); $container = new Element( 'div', [ 'class' => 'container' ] ); $render = function( $wrapper, $container ){ ob_start(); echo $wrapper->open_tag(); echo $container->open_tag(); echo '...'; echo $container->close_tag(); echo $wrapper->close_tag(); // this would have the same effect // echo $wrapper->append_child( $container->append_child( "..." )->render(); return ob_get_clean(); }; return [ $wrapper, $container, $render ]; } list( $wrapper, $container, $render ) = get_the_thing(); $wrapper->add_class( 'wide-wrapper' ); $container->before( "<h1>Above Container Title</h1>"); echo $render( $wrapper, $container );
<div class="wrapper wide-wrapper"> <h1>Above Container Title</h1> <div class="container">...</div> </div>
限制/不支持
您会注意到许多方法看起来与jQuery中的方法类似。虽然您可以更新所有元素的属性,但不能查询元素的子元素。
例如,没有 $element->querySelector( 'input[name="first_name"]' )。虽然这当然可以实现,但我目前没有计划实现它。
此外,无法从HTML字符串创建Element实例。这个过程并不简单。
ElementAttribute / 扩展性
每个Element都包含一个ElementAttribute实例数组。
ElementAttribute具有可覆盖的匿名函数来访问它们的值。
例如,'class'属性定义了'get'、'set'、'add'、'remove'、'has'。
默认情况下,style属性定义了'get'、'set'、'add'。
所有其他属性都使用默认实例(但您可以更改它)。默认实例仅定义'get'和'set'。
注意:动态'get'方法应始终返回标量值。它在渲染期间被调用。
此外,所有动态方法都可以接受可变数量的参数。
一般来说,很难知道哪些属性定义了哪些动态方法。同样,也很难知道这些动态方法的参数。这不是理想的,但这是为了灵活性而必须做出的权衡。为了处理这个事实,您可以通过扩展ElementBaseClass或Element来创建自己的定义良好的包装方法。
use JMasci\HtmlElement\Element; use JMasci\HtmlElement\ElementAttribute; Class MyElement extends Element{ // override this to modify attribute instances protected function build_attribute_instance($name){ $attr = parent::build_attribute_instance( $name ); // define your own 'remove' method on the 'style' attribute. if ( $name === 'style' ) { $attr->methods['remove'] = function( ...$args ) { // note: "$this" will be the ElementAttribute instance. }; } return $attr; } } $e = new MyElement( 'p' ); // "style" now understands "remove" $e->attr_get_instance( 'style' )->_call_dynamic_method( 'remove', 'display' );