我刚刚在这个构建中遇到了我的MVC框架的Textbox控件,在完成整个文档之前,我在从ServerTag继承的所有内容上调用PreRender(后者继承自DOMElement)。
我发现更改DOMElement派生对象的tagName的唯一方法是将其替换为新的属性,并将所有属性同步到旧的属性。
这就是代码中的样子:
protected function PreRenderTextarea( WebPage $sender )
{
$textarea = $sender->createElement( 'textarea' );
foreach( $this->attributes as $attribute )
{
if ( $attribute->name == 'value' )
{
$textarea->nodeValue = $attribute->value;
}
else
{
$textarea->setAttribute( $attribute->name, $attribute->value );
}
}
$this->parentNode->replaceChild( $textarea, $this );
}
public function OnPreRender( WebPage $sender )
{
parent::OnPreRender();
$this->setAttribute( 'value', $this->Value );
switch( $this->Mode )
{
case 'normal' :
$this->setAttribute( 'type', 'text' );
break;
case 'password' :
$this->setAttribute( 'type', 'password' );
break;
case 'multiline' :
$this->PreRenderTextarea( $sender );
return;
break;
}
}
这真的是唯一的方法吗?这种方式具有使控制背后的所有逻辑归零的相当不希望的副作用。
答案 0 :(得分:2)
是的,你必须这样做 - 原因是你不只是改变单个属性(tagName
)的值,你实际上是在将整个元素从一种类型改为另一个。 tagName
(或nodeName
)和nodeType
等属性在DOM中是只读的,并在创建元素时设置。
因此,使用DOMNode::replaceChild
创建一个新元素并使用textarea
完全取代旧元素是正确的操作。
我不确定你的意思是“废除控制背后所有逻辑的不必要的副作用” - 如果你澄清我可以在那里给你指导。
听起来你可能不希望ServerTag从DOMElement继承,而你可能想要通过其他一些模式链接这两个对象,例如组合(即所以ServerTag“有一个”DOMElement而不是“是一个” DOMElement)以便您只是替换与ServerTag Textbox对象关联的DOMElement对象。
或者更长时间的猜测是,您可能会遇到仅复制属性的问题(即rows
具有必需的属性,例如cols
和input
,{{1}}没有)。