Skip to content

视图页面逻辑拆分

我们在实现视图页面时,可能会遇到一个页面声明逻辑存在过于复杂的情况,也有可能存在多个页面共用一些逻辑的情况,这时我们可以将这些逻辑抽离出来,然后在视图页面按需引用进行复用。下面分别进行介绍。

zin 生成函数

为了对 zin 界面声明逻辑进行复用,可以将这些逻辑封装为函数,通常函数返回值可以为 zin 部分方法参数支持的类型(目前支持任何 php 类型,详情参考 部件 文档),函数通常命名为 buildXxxXxxx,参数可以根据实际需要进行定义。

在函数内使用外部变量,通常不建议在视图公共函数中使用外部变量,因为会导致 zin 生成函数的复用性变差。如需使用可以使用 global $var 来引用全局变量,或通过 data() 函数来获取 zin 数据(包括 control 方法内的数据)。

下面为一个 zin 生成函数的定义:

php
/**
 * Build project headline title
 * 构建产品标题,用于页面顶部显示
 *
 * @param object $project
 * @return mixed Any type supported by zin widget function 任何 zin 部件函数参数支持的类型
 */
function buildProjectTitle(object $project): mixed
{
    return h1($project->name);
}

自定义 zin 部件方法

有时需要对一些界面声明逻辑进行复用,除了定义 zin 生成函数,还可以定义为 zin 部件方法,这样相当于自己创建了一个新的部件,可以与其他部件方法一样进行使用。

下面为一个自定义 zin 部件方法的示例:

php
/**
 * Project list, display name and desc of project
 * 产品列表,显示每个产品的名称和描述
 *
 * Widget props definitions 部件属性定义:
 *  - array  items  Project object list 产品对象列表
 *  - string title  List title on top 列表标题
 *
 * @param mixed ...$args Any type supported by zin widget function 任何 zin 部件函数参数支持的类型
 * @return mixed Any type supported by zin widget function 任何 zin 部件函数参数支持的类型
 */
function projectList(): mixed
{
    /* 所有 zin 部件都可以拥有任意个参数,此时需要通过构造一个 item 来将参数转换为部件属性和子内容 */
    $wg = item(func_get_args());

    /* 以属性名称数组的形式定义部件支持的属性 */
    $definedProps = ['items', 'title'];

    /* 获取多个属性的值 */
    list($items, $title) = $wg->prop($definedProps);

    /* 将每个列表项对应 li 实例存储在数组内 */
    $list = [];
    foreach ($items as $item)
    {
        $list[] = li
        (
            strong($item->name),
            span($item->desc, set::class('muted')),
        );
    }

    /* 返回部件生成的 zin 结构 */
    return ul
    (
        /* 将用户设置的其他属性作为 HTML 属性传递给 ul */
        set($item->props->skip($definedProps)),

        /* 声明列表标题 */
        li(set::class('project-list-heading'), $title),

        /* 直接引用列表项声明数组 */
        $list,

        /* 展示部件内插入的其他内容 */
        $item->children()
    );
}

下面为实际用法:

php
namespace zin;

include 'common.html.php';

$myProjects = array();
$myProjects[] = array('title' => 'hello', 'desc' => 'world');
$myProjects[] = array('title' => 'foo',   'desc' => 'bar');

$otherProjects = array();
$otherProjects[] = array('title' => 'hello others', 'desc' => 'world others');
$otherProjects[] = array('title' => 'foo others',   'desc' => 'bar others');

projectList
(
    set::title('My projects'),
    set::class('shadow mb-2'),
    set::items($myProjects)
);

projectList
(
    set::title('Other projects'),
    set::items($otherProjects),
    li('others projects end'),
);

render();
html
<ul class="shadow mb-2">
  <li class="project-list-heading">My projects</li>
  <li><strong>hello</strong><span class="muted">world</span></li>
  <li><strong>foo</strong><span class="muted">bar</span></li>
</ul>
<ul>
  <li class="project-list-heading">Other projects</li>
  <li><strong>hello others</strong><span class="muted">world others</span></li>
  <li><strong>foo others</strong><span class="muted">bar others</span></li>
  <li>others projects end</li>
</ul>

模块下公共逻辑处理

创建 module/example/ui/common.html.php 文件,然后在此文件中定义 zin 生成方法来对公共逻辑进行封装,例如:

php
namespace zin;

/**
 * Build project headline title
 * 构建产品标题,用于页面顶部显示
 *
 * @param object $project
 * @return mixed Any type supported by zin widget function 任何 zin 部件函数参数支持的类型
 */
function buildProjectTitle(object $project): mixed
{
    return h1($project->name);
}

/**
 * Build project list item, includes name and description
 * 构建产品列表项,包含名称和描述
 *
 * @param object $project
 * @return mixed Any type supported by zin widget function 任何 zin 部件函数参数支持的类型
 */
function buildProjectItem(object $project): mixed
{
    return li
    (
        strong($project->name),
        span($project->desc, set::class('muted')),
    );
}

下面为在视图文件引入公共方法对示例:

php
namespace zin;

include 'common.html.php';

div
(
    buildProjectTitle($project);
    div
    (
        buildToolbarItem($project);
    )
);

render();
php
namespace zin;

include 'common.html.php';

formPanel
(
    to::heading(buildProjectTitle($project)),
    // ...
);

render();

复杂视图的拆分

有时一个视图文件非常复杂,可能包含两个相互独立的渲染逻辑,例如产品浏览页面支持按照列表浏览也支持按照卡片浏览,这时可以将两个渲染逻辑拆分成两个视图文件,然后在主视图文件中引入这两个视图文件。我们约定将主视图文件命名为 methodname.html.php,将拆分的视图文件命名为 methodname.*.html.php,例如:

ini
module/example/ui/
├── browse.html.php       # 主视图文件
├── browse.list.html.php  # 列表视图文件
└── browse.grid.html.php  # 卡片视图文件

这样我们只需要在拆分的视图文件定义 zin 生成方法,然后在主视图文件中按需引入即可,下面为一个实际的例子:

php
namespace zin;

include "browse.$browseType.html.php";

buildBrowsePage();

render();
php
namespace zin;

/**
 * Build browse page with list view
 * 构建列表视图的产品浏览页面
 *
 * @return mixed
 */
function buildBrowsePage()
{
    return dtable
    (
        // ...
    );
}
php
namespace zin;

/**
 * Build browse page with grid view
 * 构建列表视图的产品浏览页面
 *
 * @return mixed
 */
function buildBrowsePage()
{
    return grid
    (
        // ...
    );
}

https://zentao.net