首页>建站相关>Typecho开发文档-Widget设计文档

Typecho开发文档-Widget设计文档

什么是Widget

Widget是组成Typecho的最基本元素,除了已经抽象出来的类库外,其它几乎所有的功能都会通过Widget来完成.在实践中我们发现,在博客这种小型但很灵活的系统中实施一些大型框架的思想是不合适的,它会使系统灵活性降低并且维护成本增高.因此为了达到功能和抽象的统一,我们将系统中所有的功能单元都看作一个Widget,它们都继承自一个超类'TypechoWidget'.

如何调用Widget

Widget有两种调用方法.它们分别是

  • 显式地初始化一个Widget实例.
class Foo extends Typecho_Widget
{
    public function test()
    {
        echo 'hello world';
    }

    public function render($a, $b)
    {
        echo $a + $b;
    }
}

$widget = new Foo();
  • 使用工厂函数factory初始化Widget,并运行入口函数.
Typecho_API::factory('Foo', 6, 8);
//outputs: 14

在系统中,我们通常使用后者来实例化一个Widget -> Typecho::widget函数将直接返回一个实例化的Widget对象.它的第一个参数是Widget的绝对名称,在Typecho系统中Widget有两个存放的地方,他们分别是./widget目录和./var/plugins目录.Widget与其文件名保持一致且区分大小写,比如一个Widget的名称为TestMe那么它的文件名就是TestMe.php.

Widget文件可以按目录存放,调用的时候用点分号分割目录.比如存放路径为./widget/contents/TestPost.php,调用方法就是

Typecho::widget('contents.TestPost');

在上面的解释中,我们提到widget函数的作用是实例化一个Widget并运行它的入口函数.Widget的入口函数是render,这是一个公开函数,子类在继承超类TypechoWidget时必须实现这一方法.因此widget函数后面的参数将传递给入口函数render,比如上例中的Typecho::widget('Foo',6,8),后面的两个参数将传递给Foo::render($a, $b).

何时调用

Widget通常在以下三个地方被调用.

  • 默认组件.Typecho系统共有两个入口(前台和后台),在这两个入口初始化的时候分别会运行一些必要的默认组件,在index.php中有以下代码
Typecho::widget('Options')->to($options);    //初始化配置组件
Typecho::widget('Access')->to($access);      //初始化权限组件
</code>在./admin/header.php中有以下代码<code php>Typecho::widget('Options')->to($options);    //初始化配置组件
Typecho::widget('Access')->to($access);      //初始化权限组件
Typecho::widget('Menu')->to($menu);          //初始化菜单组件

这些Widget在系统初始化时被强制执行.

  • 通过路由器默认执行的组件.[[develop:route|路由器]]是系统的重要组成部分,前台的所有页面都会通过路由器来展现,路由器在默认组件执行之后被执行.我们可以在路由表中设置默认执行的组件,这样当页面被导向这条路由记录时,默认组件将被执行.下面是一个路由表的示例,你可以在./config.php中找到它的完整定义
/** 定义路由结构 **/
global $route;

$route = array(
    'index'         =>  array('/', 'index.php', NULL, NULL, array('contents.Posts')),   //最后的一个参数表示默认组件
    'index_page'    =>  array('/page/([0-9]+)[/]?', 'index.php', array('page'), '/page/%d', array('contents.Posts')),
    'post'          =>  array('/archives/([0-9]+)[/]?', 'post.php', array('cid'), '/archives/%d', array('contents.Post')),
    'rss'           =>  array('/feed[/]?', '../../xml/rss.php', NULL, '/rss', NULL),
    'do'            =>  array('/([_0-9a-zA-Z-]+)\.do?', array('DoWidget'), array('do'), '/%s.do'),
    'job'           =>  array('/([_0-9a-zA-Z-]+)\.job?', array('JobWidget'), array('job'), '/%s.job'),
    'login'         =>  array('/login[/]?', 'admin/login.php'),
    'admin'         =>  array('/admin[/]?', 'admin/index.php'),
    'page'          =>  array('/([_0-9a-zA-Z-]+)[/]?', 'page.php', array('slug'), '/%s', array('contents.Post')),
);
  • 在最终页面中被执行的组件.最终页面也就是开发者最常接触到的模板之类的页面,我们通过widget函数来调用我们需要的组件.
<html>
<head>
<title><?php $options->title(); ?></title>
</head>
<body>

<div>
<!-- 第一种调用方法,调用公开方法生成列表 -->
<?php Typecho::widget('contents.Posts')->output('li', '_blank', 'list', true, 10, '[...]'); ?>

<!-- 第二种调用方法,调用集成方法生成列表 -->
<?php Typecho::widget('contents.Posts')->parse('<li><a href="{permalink}">{title}</a></li>'); ?>

<!-- 第三种调用方法,每行输出 -->
<?php Typecho::widget('contents.Posts')->to($posts); ?>

<?php while($posts->get()): ?>

    <h2><a href="<?php $posts->permalink(); ?>"><?php $posts->title(); ?></a></h2>
    
    <cite><?php $post->date('Y-m-d'); ?> | <?php $post->category(','); ?></cite>
    
    <div><?php $post->content('阅读更多...'); ?></div>

<?php endwhile; ?>
</div>
</body>
</html>

由于widget函数将直接返回实例化的组件(Widget)对象,因此我们可以通过返回值直接使用Widget的公开方法.其中一些比较特殊的方法将在后面被陆续介绍到.

一次执行规则

什么是一次执行规则

当一个组件被实例化以后,它将被保存在对象堆栈中,当我们第二次使用这一组件时,它将被直接从堆栈中取出然后返回.这一规则可以在保证组件唯一性的同时节约服务器资源.

如何调用已经被实例化的组件

一般来说我们通过函数widget调用一个组件时,它会返回一个实例化组件,你不必担心它是否是第一次被实例化.

Widget内部方法与接口

to方法

to方法是一个非常有用的伪方法,它的作用在于把一个实例化的Widget赋到一个变量中.我们可以通过以下代码来展示

Typecho::widget('Foo')->to($foo);
$foo->test();

在上面的代码中我们通过to方法把实例化的Foo组件赋值给$foo.这样我们在后面的代码中可以用$foo变量来代表实例化的Foo对象,它等效于

$foo = Typecho::widget('Foo');

之所以不直接使用赋值语法,是因为赋值在模板中会经常用到,这一简写语法比较好理解,可以简化模板语法.to方法在超类TypechoWidget中被实现,通过继承TypechoWidget可以自动具备这一方法.

push以及相关方法

每个Widget都有一个内部队列,用于存储多行数据,这个堆栈的数据存取方法在超类TypechoWidget中被实现,我们通过继承超类获得对队列的操作能力。每次执行push方法,都将把一行数据压入队列,并移动队列的指针。数据压入完毕后,我们可以通过get方法移动指针,并且通过直接访问组建的内部属性获得某行的具体数据,我们通过如下代码来展示这一过程

class Foo extends TypechoWidget
{
    public function render()
    {
        //定义三行数据
        $row1 = array('name' => 'Mike', 'age' => 17, 'sex' => 'man');
        $row2 = array('name' => 'Lucy', 'age' => 27, 'sex' => 'woman');
        $row3 = array('name' => 'Clark', 'age' => 23, 'sex' => 'man');

        //按顺序压入队列
        $this->push($row1);
        $this->push($row2);
        $this->push($row3);

        //从队列中取出相应值
        while($this->get())
        {
            echo "My name is " . $this->name . ", I'm " . $this->age . " years old, I am a " . $this->sex . ".\r\n";
        }
    }
}

/***
输出:
My name is Mike, I'm 17 years old, I am a man.
My name is Lucy, I'm 27 years old, I am a woman.
My name is Clark, I'm 23 years old, I am a man.
***/

parse方法

parse方法实际上是对队列内数据输出的改善,以方便用户在html视图模板页面中显示列表,你不需要使用while之类的循环语法,直接指定一个列表模板即可,此函数会按照模板直接输出列表。因此我们可以对上面的例子做一点改进,用更少的代码达到同样的效果。

class Foo extends TypechoWidget
{
    public function render()
    {
        //定义三行数据
        $row1 = array('name' => 'Mike', 'age' => 17, 'sex' => 'man');
        $row2 = array('name' => 'Lucy', 'age' => 27, 'sex' => 'woman');
        $row3 = array('name' => 'Clark', 'age' => 23, 'sex' => 'man');

        //按顺序压入队列
        $this->push($row1);
        $this->push($row2);
        $this->push($row3);

        //使用parse输出
        $this->parse("My name is {name}, I'm {age} years old, I am a {sex}.");
    }
}

/***
输出:
My name is Mike, I'm 17 years old, I am a man.
My name is Lucy, I'm 27 years old, I am a woman.
My name is Clark, I'm 23 years old, I am a man.
***/

alt方法

在视图中输出widget列表内容时,可能产生如下隔行输出不同风格的需求.

<ul>
<li class="style-one">hello world</li>
<li class="style-two">hello china</li>
<li class="style-one">hello earth</li>
<li class="style-two">hello moon</li>
</ul>

注意以上代码中class的内容,也就是以2为界的循环输出.我们可以通过调用alt方法达到目的.

<?php Typecho::widget('Hello')->to($hello); ?>

<?php while($hello->get()): ?>
<li class="<?php $hello->alt('style-one', 'style-two'); ?>"><?php $hello->word(); ?></li>
<?php endwhile; ?>

我们在上述代码中使用了alt方法,alt方法接受不定数目的参数,也就是说你可以给它传递任意个数的参数,它将按照你传递参数的个数循环输出这些参数。

摘自

Typecho官方Widget设计文档

标签: typecho

移动端可扫我直达哦~

推荐阅读

typecho 2024-04-20

typecho根据标签的slug name信息判断是否输出免责声明

博主是从事机械行业的,工作过程中接触了很多二手老旧的设备,因为是二手设备,不缺胳膊少腿能正常运行已是难得,完善的说明书与售后服务想都不要想了。所以找设备的说明书成了一项附加的工作,总得让设备正常运行起来,偶尔设备有个小病小痛的,也不能...

建站相关 typecho

typecho 2023-10-25

Typecho默认路由表一览

路由器(Route)路由器(Route)是Typecho系统中的一个重要组件,类似mod_rewrite的机制,来实现独立的URL和指定的controller/action/params的映射规则.它通过识别诸如http://loca...

建站相关 typecho

typecho 2023-10-21

Typecho自动更新指定文章内容的尝试

曾经在老的博客(wordpress)里尝试并且成功运行过的一个方案,定时去请求某个比如“每天60秒读懂世界”这样的api,获取到数据,然后根据数据更新某一篇博文的内容。因为有“轻微”的强迫症,所以习惯把不用的东西直接“rm -rf”删...

建站相关 typecho

typecho 2023-10-21

Typecho数据库常用API

表的创建和删除在Typecho插件开发过程中,往往需要创建自己的表。上文提到Typecho_Db类中的query函数,可用于执行所有sql语句,因此我们使用query()来进行表的创建、修改或者删除。$db= Typecho_Db::...

建站相关 typecho

typecho 2023-10-18

让typecho博客支持显示数学公式

MathJax是一个开源的基于Ajax的数学公式显示的解决方案,结合多种先进的Web技术,支持主流的浏览器。MathJax根据页面中定义的LaTex数据,生成对应的数学公式。具体可见:mathjax项目代码(GitHub)因为是利用j...

建站相关 typecho

typecho 2023-10-15

为Typecho编辑器增加HTML标签支持

这几天为Typecho编辑器基本不支持块级元素而困扰,在github上翻编辑器插件的时候意外看到有位望友说可以去修改Hyperdown.php文件以增加对HTML标签的支持。该文件位于:build/var/HyperDown.php需...

建站相关 typecho

typecho 2023-10-12

typecho为什么更换主题后部分图片无法正确显示

其实严格的说,这可能是博主自己主题的问题,但人类的悲欢偶尔相通么,没准也可能在其他的主题中遇到类似的。博主之前边写博客边修改拼凑了一个比较简陋的主题,使用一段时间后,觉得主页过于单调了,于是在23年的国庆前后对主题整体做了一个比较大的...

建站相关 typecho

typecho 2023-10-05

typecho输出标签云或生成热门标签

小鸟数据生成标签云的代码应该是仿自默认的纯白主题,为了显示彩色标签,所以为tags增加了几个随机的类,事实上这几个类完全可以利用jquery在前端添加,毕竟现在用户的电脑性能远远超过了自己小水管服务器的性能,php添加随机类的写法:&...

建站相关 typecho