该包最新版本(v1.1.0)没有提供许可证信息。

Nette 框架的额外组件行为

v1.1.0 2015-01-16 02:53 UTC

This package is auto-updated.

Last update: 2024-09-13 20:17:01 UTC


README

该库包含了一些有用的 Nette 框架 UI 扩展。

Zax\Application\UI\IAjaxAware

定义了一个方法 enableAjax(),显然是为了启用 AJAX 功能。

Zax\Application\UI\Control

这个类扩展了标准的 Nette 控件,并添加了一些有趣的功能,包括 IAjaxAware 实现和视图。其主要目的是在我们执行一些常见任务时节省重复的样板代码,并使得组件的 AJAX 化变得更容易,并且结果一致。

示例

一个非常简单的组件可能看起来像这样

class SomeControl extends Zax\Application\UI\Control {

	public function beforeRender() {
		// gets called before a component gets rendered
	}

	public function viewDefault() {
		// gets called only if view is "Default"
	}

}

组件也需要一个模板。所以让我们在组件所在的 'templates' 目录中添加一个 'Default.latte'。结构将如下所示

  • SomeControl.php
  • /templates
    • Default.latte

就是这样!

使用视图

视图由 view<View> 方法定义。如果您尝试访问一个未定义的视图,将抛出一个异常。另外,每个视图都有一个同名的模板。

视图内部实际上只是一个持久的参数 $view,因此创建指向视图的链接 couldn't be any easier。

$this->link('this', ['view' => 'Foo']);

使用渲染

在 Nette 中,我们有时可能想使用类似这样的事物:{control someControl:foo}。通常,我们会创建一个 renderFoo 方法,但这个组件基于 __call 魔法方法,所以这不会正常工作。相反,让我们调用我们的方法 beforeRenderFoo。同样,它需要一个单独的模板,假设我们仍在 "Default" 视图中,那么模板将是 'Default.Foo.latte'。

模板命名的模式是 '<View>.latte' 或 '<View>.<Render>.latte'。

我们也可以向渲染传递参数,因此 {control someControl:foo, bar => val} 将调用 beforeRenderFoo 方法并将 "val" 传递给名为 "bar" 的参数。

处理 AJAX

我不会绕弯子。AJAX 是神奇的,它就是为了满足我的需求而设计的,所以你可能会在这里发现一些 WTF 因素。但既然我已经花时间实现了它,我也可以记录它。

首先我们需要做的是在我们的新创建的组件上调用 enableAjax(在 createComponent* 方法中),并在我们的组件模板中用 {snippet}(不带名称)包裹我们的组件。从现在起,当我们发送 AJAX 请求时,组件应该自动重新绘制它的片段。请注意,这将启用所有子组件的 AJAX(嗯,对于所有实现 IAjaxAware 的子组件)。

已知限制: Nette 按需创建组件。这意味着,如果一个组件在请求期间没有接收到任何参数,它将在在模板中需要它之后创建,这对于 AJAX 重绘来说太晚了。一个简单的解决方案是在操作中手动创建组件,如下所示

public function actionDefault() {
	$this->createComponent('someControl');
	// or shorter
	$this['someControl'];
}

好的,现在我们有一个了解 AJAX 并且知道 AJAX 是否启用的组件。现在是我们创建一些尊重这些设置的链接的时候了。有两种方法可以做到这一点,一种是尊重默认的 nette.ajax.js 设置,但需要更多的样板代码,另一种是使用 n:ajax 宏。

要使用第一种方法,只需在添加类 "ajax" 到您的链接之前检查 $control->isAjaxEnabled()(或由于 Nette\Object 魔法 $control->ajaxEnabled),如下所示

<a n:href="this, view => Foo" n:class="$control->ajaxEnabled ? ajax">link</a>

另一种方法在模板中看起来更加优雅

<a n:href="this, view => Foo" n:ajax>link</a>

这个n:macro在你的组件上执行相同的检查,但它不是添加一个类,而是添加data-zax-ajax属性。为了使其工作,我们需要在配置中注册一个扩展,并在这个js代码之前添加以下代码:

extensions:
	ajax: Zax\DI\AjaxExtension

before calling $.nette.init()

$.nette.ext('init').linkSelector = 'a[data-zax-ajax]';

简单吧?现在,还有一个问题要讨论。如果你曾经尝试过将你的应用AJAX化,你可能已经走过一条路,那就是不断地写if is ajax, redraw, else redirect,通常你只能在信号中使用AJAX,因为当你设置持久性参数或类似的东西时,你不能调用redrawControl

我也走过那条路,真的很糟糕。我们已经有自动片段无效化,这解决了持久性参数部分,但关于if is ajax blahblahblah呢?好吧,我添加了一个名为go的方法,它为我们执行这个检查,并确保无论是否是AJAX请求,我们都能到达同一个目的地。

所以调用$this->go('signal!', ['view' => 'Foo']);将检查是否是AJAX请求,如果是,则执行常规重定向到信号和Foo视图,否则直接将我们转发到相同的目的地,而不会发出额外的请求。这再简单不过了!

Zax\Application\UI\Multiplier

Multiplier是一个小巧的类,允许我们在一个页面上拥有同一组件的多个实例。但是默认的Nette Multiplier会阻止子组件接收ajaxEnabled状态,因为它不是IAjaxAware。所以我把它变成了IAjaxAware

自定义

控制行为被划分为几个特质

TControlForward

forward()presenterForward()方法。

TControlAjax

IAjaxAware实现+TControlForward

TControlLifeCycle

使用__call进行生命周期管理,调用view*()beforeRender*(),并添加一个持久参数$view。此外,如果控制实现IHasControlLifeCycle,则自动调用run()方法,我们可以使用该方法来渲染模板或做任何我们想做的事情。

TControlMergeLinkParams

允许我们在特定的组件中指定$defaultLinkParams,以在使用多个(子)组件和持久参数时尽可能保持URL的清洁。