typecho中的Widget设计文档

news2025/5/12 18:49:21

组成系统的最基本元素

什么是Widget

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

如何调用Widget

Widget有两种调用方法,它们分别是
1、显式地初始化一个Widget实例

class Foo extends Typecho_Widget
{
    public function test()
    {
        echo 'hello world';
    }
         
    public function render($a, $b)
    {
        echo $a  $b;
    }
}
         
    $widget = new Foo();

2、使用工厂函数**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通常在以下三个地方被调用。

1、默认组件。Typecho系统共有两个入口(前台和后台),在这两个入口初始化的时候分别会运行一些必要的默认组件,在index.php中有以下代码

Typecho::widget('Options')->to($options);    //初始化配置组件
Typecho::widget('Access')->to($access);      //初始化权限组件

在./admin/header.php中有以下代码

Typecho::widget('Options')->to($options);    //初始化配置组件
Typecho::widget('Access')->to($access);      //初始化权限组件
Typecho::widget('Menu')->to($menu);          //初始化菜单组件

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

2、通过路由器默认执行的组件。[[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')),
         );

3、在最终页面中被执行的组件。最终页面也就是开发者最常接触到的模板之类的页面,我们通过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方法接受不定数目的参数,也就是说你可以给它传递任意个数的参数,它将按照你传递参数的个数循环输出这些参数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2374129.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL索引原理以及SQL优化(二)

目录 1. 索引与约束 1.1 索引是什么 1.2 索引的目的 1.3 索引分类 1.3.1 数据结构 1.3.2 物理存储 1.3.3 列属性 1.3.4 列的个数 1.4 主键的选择 1.5 索引使用场景 1.6 索引的底层实现 1.6.1 索引存储 1.6.2 页 1.6.3 B 树 1.6.4 B 树层高问题 1.6.5 自增 id 1.7 innod…

MATLAB中矩阵和数组的区别

文章目录 前言环境配置1. 数据结构本质2. 运算规则&#xff08;1&#xff09;基本运算&#xff08;2&#xff09;特殊运算 3. 函数与操作4. 高维支持5. 创建方式 前言 在 MATLAB 中&#xff0c;矩阵&#xff08;Matrix&#xff09; 和 数组&#xff08;Array&#xff09; 的概…

Desfire Ev1\Ev2\Ev3卡DES\3K3DES\AES加解密读写C#示例源码

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?spma21dvs.23580594.0.0.1d292c1bYhsS9c&ftt&id917152255720 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using S…

MySQL核心内容【完结】

MySQL核心内容 文章目录 MySQL核心内容1.MySQL核心内容目录2.MySQL知识面扩展3.MySQL安装4.MySQL配置目录介绍Mysql配置远程ip连接 5.MySQL基础1.MySQL数据类型1.数值类型2.字符串类型3.日期和时间类型4.enum和set 2.MySQL运算符1.算数运算符2.逻辑运算符3.比较运算符 3.MySQL完…

C++类和对象进阶 —— 与数据结构的结合

&#x1f381;个人主页&#xff1a;工藤新一 &#x1f50d;系列专栏&#xff1a;C面向对象&#xff08;类和对象篇&#xff09; &#x1f31f;心中的天空之城&#xff0c;终会照亮我前方的路 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 文章目录 […

Django之账号登录及权限管理

账号登录及权限管理 目录 1.登录功能 2.退出登录 3.权限管理 4.代码展示合集 这篇文章, 会讲到如何实现账号登录。账号就是我们上一篇文章写的账号管理功能, 就使用那里面已经创建好的账号。这一次登录, 我们分为三种角色, 分别是员工, 领导, 管理员。不同的角色, 登录进去…

EXCEL中嵌入其他表格等文件

在EXCEL中嵌入其他表格 先放链接&#xff1a;https://jingyan.baidu.com/article/295430f11708c34d7e00509a.html 步骤如下&#xff1a; 1、打开一个需要嵌入新表格的excel表。 2、切换至“插入”菜单中&#xff0c;单击选择“对象”。 3、如下图所示&#xff0c;会弹出“对象…

21. LangChain金融领域:合同审查与风险预警自动化

引言&#xff1a;当AI成为24小时不眠的法律顾问 2025年某商业银行的智能合同系统&#xff0c;将百万级合同审查时间从平均3周缩短至9分钟&#xff0c;风险条款识别准确率达98.7%。本文将基于LangChain的金融法律框架&#xff0c;详解如何构建合规、精准、可追溯的智能风控体系…

Springboot使用事件流调用大模型接口

什么是事件流 事件流&#xff08;Event Stream&#xff09; 是一种处理和传递事件的方式&#xff0c;通常用于系统中的异步消息传递或实时数据流。在事件驱动架构&#xff08;Event-Driven Architecture&#xff09;中&#xff0c;事件流扮演着至关重要的角色。 事件流的概念…

计算机网络--2

TCP三次握手 TCP连接为什么需要三次握手 1. 由于网络情况复杂,可能会出现丢包现象,如果第二次握手的时候服务器就认为这个端口可用,然后一直开启,但是如果客户端未收到服务器发送的回复,那么就会重新发送请求,服务器就会重新开启一个端口连接,这样就会浪费一个端口。 三…

尤雨溪宣布:Vue 生态正式引入 AI

在前端开发领域,Vue 框架一直以其易用性和灵活性受到广大开发者的喜爱。 而如今,Vue 生态在人工智能(AI)领域的应用上又迈出了重要的一步。 尤雨溪近日宣布,Vue、Vite 和 Rolldown 的文档网站均已添加了llms.txt文件,这一举措旨在让大型语言模型(LLM)更方便地理解这些…

蓝桥杯第十六届c组c++题目及个人理解

本篇文章只是部分题目的理解&#xff0c;代码和思路仅供参考&#xff0c;切勿当成正确答案&#xff0c;欢迎各位小伙伴在评论区与博主交流&#xff01; 题目&#xff1a;2025 题目解析 核心提取 要求的数中至少有1个0、2个2、1个5 代码展示 #include<iostream> #incl…

硬件工程师笔记——电子器件汇总大全

目录 1、电阻 工作原理 欧姆定律 电阻的物理本质 一、限制电流 二、分压作用 三、消耗电能&#xff08;将电能转化为热能&#xff09; 2、压敏电阻 伏安特性 1. 过压保护 2. 电压调节 3. 浪涌吸收 4. 消噪与消火花 5. 高频应用 3、电容 工作原理 &#xff08;…

微软推动智能体协同运作:支持 A2A、MCP 协议

今日凌晨&#xff0c;微软宣布 Azure AI Foundry 和 Microsoft Copilot Studio 两大开发平台支持最新 Agent 开发协议 A2A&#xff0c;并与谷歌合作开发扩大该协议&#xff0c;这一举措对智能体赛道意义重大。 现状与变革意义 当前智能体领域类似战国时代&#xff0c;各家技术…

Linxu实验五——NFS服务器

一.NFS服务器介绍 NFS服务器&#xff08;Network File System&#xff09;是一种基于网络的分布式文件系统协议&#xff0c;允许不同操作系统的主机通过网络共享文件和目录3。其核心作用在于实现跨平台的资源透明访问&#xff0c;例如在Linux和Unix系统之间共享静态数据&#…

20242817李臻《Linux⾼级编程实践》第9周

20242817李臻《Linux⾼级编程实践》第9周 一、AI对学习内容的总结 第十章 Linux下的数据库编程 10.1 MySQL数据库简介 MySQL概述&#xff1a;MySQL是一个开源的关系型数据库管理系统&#xff0c;最初由瑞典MySQL AB公司开发&#xff0c;后经SUN公司收购&#xff0c;现属于O…

开源分享:TTS-Web-Vue系列:SSML格式化功能与高级语音合成

&#x1f3af; 本文是TTS-Web-Vue系列的第十二篇文章&#xff0c;重点介绍项目新增的SSML格式化功能以及SSML在语音合成中的应用。通过自动格式化和实时预览&#xff0c;我们显著提升了SSML编辑体验&#xff0c;让用户能够更精确地控制语音合成的细节&#xff0c;实现更自然、更…

FAST-LIO笔记

1.FAST-LIO FAST-LIO 是一个计算效率高、鲁棒性强的激光-惯性里程计系统。该系统通过紧耦合的迭代扩展卡尔曼滤波器&#xff08;IEKF&#xff09;将激光雷达特征点与IMU数据进行融合&#xff0c;使其在快速运动、噪声较大或环境复杂、存在退化的情况下仍能实现稳定的导航。 1…

软考中级软件设计师——UML(统一建模语言)篇

UML的词汇表包含3种构造块:事物、关系和图。事物是对模型中最具有代表性的成分的抽象;关系把事物结合在一起;图聚集了相关的事物。 一、事物 UML 事物是模型中的基本元素&#xff0c;分为 结构事物、行为事物、分组事物、注释事物。 1. 结构事物 类&#xff08;Class&#x…

TSN网络与DIOS融合:破解煤矿井下电力系统越级跳闸难题

一、引言 1.1 研究背景与意义 在现代煤矿生产中&#xff0c;井下电力系统作为整个煤矿生产的动力核心&#xff0c;其重要性不言而喻。煤矿井下的各类机械设备&#xff0c;如采煤机、刮板输送机、通风机、排水泵等&#xff0c;都依赖稳定的电力供应才能正常运行。电力系统的稳定…