widget好处是方面重用和灵活移动。CWidget是所有的widge父类,同时它又是是CBaseController的子类,CWidget提供了类似CController中的一些方法,但render()方法渲染的时候不带layout,而且渲染的时候$this指得是CWidget对象,而不是CController对象,CController对象可以通过其中的getController()方法获取,用其子类中需要对init()和run()方法重载以定制不同的挂件。
CBaseController提供widget()方法以及beginWidget()、endWidget()方法加载挂件。
public function widget($className,$properties=array(),$captureOutput=false) { if($captureOutput) { ob_start(); ob_implicit_flush(false); $widget=$this->createWidget($className,$properties); $widget->run(); return ob_get_clean(); } else { $widget=$this->createWidget($className,$properties); $widget->run(); return $widget; } } public function createWidget($className,$properties=array()) { $widget=Yii::app()->getWidgetFactory()->createWidget($this,$className,$properties); $widget->init(); return $widget; }上面是直接加载挂件方法,通过第三个参数来决定是返回内容还是直接输出内容,widget是通过CWidgetFactory来创建。
$this->breadcrumbs=array( 'Users', ); $this->widget('zii.widgets.CBreadcrumbs', array( 'links'=>$this->breadcrumbs, ));
通过CBaseController的widget()方法,创建CBreadcrumbs挂件,初始化后,执行run()方法渲染内容。
/** * Renders the content of the portlet. */ public function run() { if(empty($this->links)) return; echo CHtml::openTag($this->tagName,$this->htmlOptions)."\n"; $links=array(); if($this->homeLink===null) $links[]=CHtml::link(Yii::t('zii','Home'),Yii::app()->homeUrl); else if($this->homeLink!==false) $links[]=$this->homeLink; foreach($this->links as $label=>$url) { if(is_string($label) || is_array($url)) $links[]=CHtml::link($this->encodeLabel ? CHtml::encode($label) : $label, $url); else $links[]='<span>'.($this->encodeLabel ? CHtml::encode($url) : $url).'</span>'; } echo implode($this->separator,$links); echo CHtml::closeTag($this->tagName); }
<?php $this->beginContent('//layouts/main'); ?> <div id="content"> <?php echo $content; ?> </div><!-- content --> <?php $this->endContent(); ?>代码中beginContent($view=null,$data=array())其实是对beginWidget('CContentDecorator',array('view'=>$view, 'data'=>$data))再次封装,创建内容装饰挂件CContentDecorator,把主视图传进去,