clickfwd/yoyo

用于构建动态界面和前后端无缝通信的框架。

0.10.1 2024-08-29 14:33 UTC

README

Yoyo 是一个全栈 PHP 框架,您可以在任何项目中使用它来创建使用服务器端渲染的 HTML 的丰富动态界面。

使用 Yoyo,您可以创建无需编写任何 JavaScript 代码即可无缝更新的响应式组件。

Yoyo 随带一个简单的模板系统,并提供了对 Blade 的内置支持,无需使用 Laravel,以及对 Twig 的支持。

受到 Laravel LivewireSprig 的启发,并使用 htmx

🚀 Yoyo 示例应用

查看 Yoyo 示例应用 以更好地了解您可以使用 Yoyo 构建的内容。它展示了多种类型的 Yoyo 组件。您还可以克隆并安装示例应用

文档

工作原理

Yoyo 组件在页面加载时渲染,可以根据用户交互和特定事件进行单独更新,无需页面刷新。

组件更新请求直接发送到 Yoyo 指定的路由,该路由处理请求,然后将更新后的组件 HTML 部分发送回浏览器。

Yoyo 可以从服务器端直接更新浏览器 URL 状态并触发浏览器事件。

以下是一个计数器组件的示例

组件类

# /app/Yoyo/Counter.php

<?php 
namespace App\Yoyo;

use Clickfwd\Yoyo\Component;

class Counter extends Component
{
	public $count = 0;
	
	protected $props = ['count'];

    public function increment()
    {
        $this->count++;
    }
}

组件模板

<!-- /app/resources/views/yoyo/counter.php -->

<div>

	<button yoyo:get="increment">+</button>
	
	<span><?php echo $count; ?></span>

</div>

是的,就这么简单!上面要注意的一点是使用受保护的属性 $props。这表示 Yoyo,变量 count(在模板中未明确提供)应该在每个请求中持久化和更新。

安装

安装包

composer require clickfwd/yoyo

Phalcon 框架安装

对于 phalcon,您需要添加 di

$di->register(new \Clickfwd\Yoyo\YoyoPhalconServiceProvider());	

并需要添加路由

$router->add('/yoyo', [
            'controller' => 'yoyo',
            'action' => 'handle',
        ]);

您应该创建一个控制器并从 Clickfwd\Yoyo\PhalconController 类继承。

更新

执行常规 composer update 后,请记住根据 加载资源 指令更新 yoyo.js 脚本。

配置 Yoyo

需要使用一些配置设置启动 Yoyo。以下代码应在渲染和更新组件时运行。

use Clickfwd\Yoyo\View;
use Clickfwd\Yoyo\ViewProviders\YoyoViewProvider;
use Clickfwd\Yoyo\Yoyo;

$yoyo = new Yoyo();

$yoyo->configure([
  'url' => '/yoyo',
  'scriptsPath' => 'app/resources/assets/js/',
  'namespace' => 'App\\Yoyo\\'
]);

// Register the native Yoyo view provider 
// Pass the Yoyo components' template directory path in the constructor

$yoyo->registerViewProvider(function() {
  return new YoyoViewProvider(new View(__DIR__.'/resources/views/yoyo'));
});

'url'

将用于请求组件更新的绝对或相对 URL。

'scriptsPath'

复制 yoyo.js 脚本的位置。

'namespace'

这是用于发现自动加载的动态组件(使用 PHP 类的组件)的 PHP 类命名空间。

如果未提供命名空间或组件位于不同的命名空间中,您需要手动注册它们。

$yoyo->registerComponents([
    'counter' => App\Yoyo\Counter::class,
];

您需要在运行时加载组件类,可以使用 require 语句加载组件的 PHP 类文件,或者将您的组件命名空间包含在项目的 composer.json 文件中。

匿名组件无需注册,但模板名称需要与组件名称匹配。

加载资源

在以下供应商路径中找到 yoyo.js 并将其复制到您的项目公共资源目录。

/vendor/clickfwd/yoyo/src/assets/js/yoyo.js 

要将必要的脚本加载到您的模板中,请将以下代码添加到 <head> 标签内

<?php yoyo_scripts(); ?>

创建组件

动态组件需要一个类和一个模板。当使用 Blade 和 Twig 视图提供者时,您还可以使用内联视图,组件的标记直接在组件的 render 方法中返回。

匿名组件允许仅使用模板文件创建组件。

要创建一个简单的搜索组件,该组件从服务器检索结果并更新自身,请创建组件模板

// resources/views/yoyo/search.php

<form>
    <input type="text" name="query" value="<?php echo $query ?? ''; ?>">
    <button type="submit">Submit</button>
</form>

Yoyo 将渲染组件输出并将其编译,添加必要的属性以使其动态和响应式。

当您提交表单时,表单数据将自动在组件模板中可用。模板代码可以扩展以显示结果列表或空状态

<?php
$query = $query ?? '';
$entries = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
$results = array_filter($entries, function($entry) use ($query) {
    return $query && strpos($entry, $query) !== false;
});
?>
<form>
    <input type="text" name="query" value="<?php echo $query; ?>">
    <button type="submit">Submit</button>
</form>
    
<ul>
    <?php if ($query && empty($results)): ?>
        <li>No results found</li>
    <?php endif; ?>
    
    <?php foreach ($results as $entry): ?>
        <li><?php echo $entry; ?></li>
    <?php endforeach; ?>
</ul>

$results 数组可以从任何来源填充(例如数据库、API 等)

将此示例转换为具有 300ms 防抖的实时搜索输入,以最小化请求数量。将 form 标签替换为

<input yoyo:on="keyup delay:300ms changed" type="text" name="query" value="<?php echo $query; ?>" />

yoyo:on="keyup delay:300ms change" 指令告诉 Yoyo 在 keyup 事件上发起请求,具有 300ms 防抖,并且仅在输入文本更改时。

现在让我们使用一个类将其转换为动态组件。

# /app/Yoyo/Search

<?php

namespace App\Yoyo;

use Clickfwd\Yoyo\Component;

class Search extends Component
{
	public $query;
	
	protected $queryString = ['query'];
	
	public function render()
	{
		$query = $this->query;
	
		// Perform your database query
		$entries = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
	
		$results = array_filter($entries, function($entry) use ($query) {
			return $query && stripos($entry, $query) !== false;
		});
	
	  // Render the component view
		return $this->view('search',['results' => $results]);
	}
}

以及模板

<!-- /app/resources/views/yoyo/search.php -->

<input yoyo:on="keyup delay:300ms changed" type="text" name="query" value="<?php echo $query; ?>" />

<ul yoyo:ignore>
    <?php if ($query && empty($results)): ?>
        <li>No results found</li>
    <?php endif; ?>
    
    <?php foreach ($results as $entry): ?>
        <li><?php echo $entry; ?></li>
    <?php endforeach; ?>
</ul>

这里有一些需要注意的事情,在其它部分有更详细的说明。

  1. 组件类包含一个 queryString 属性,告诉 Yoyo 在组件更新后自动将 queryString 值包含在浏览器 URL 中。如果您重新加载带有 URL 中的 query 值的页面,您将自动在页面上看到搜索结果。
  2. Yoyo 将自动将组件类的公共属性作为模板变量提供。这允许使用 $this->query 在组件中访问搜索关键字,并在模板中使用 $query

当您将此搜索示例与开头的计数器示例进行比较时,您可以看到没有动作方法(即增量、减量)。组件更新始终默认为 render 方法,除非通过方法属性(即 yoyo:get、yoyo:post 等)指定了动作。在这种情况下,动作方法总是在渲染方法之前运行。

渲染组件

组件渲染有两种情况。页面加载时和组件更新时。

页面加载时的渲染

要在页面加载时在模板中渲染任何组件,请使用 yoyo_render 函数并将组件名称作为第一个参数传递。

<?php echo yoyo_render('search'); ?>

对于动态组件,组件名称是类名的连字符版本(例如 LiveSearch → live-search)。如果您在启动 Yoyo 时使用 registerComponents 方法注册组件,则可以使用注册的别名作为组件名称。

$yoyo->registerComponent('search', App\Yoyo\LiveSearch::class);

对于匿名组件,组件名称应与模板名称匹配,不带文件扩展名。因此,如果模板名称是 form.php,则可以以以下方式渲染组件

<?php echo yoyo_render('form'); ?>

更新时的渲染

使用 yoyo_update 函数自动处理组件请求并输出更新的组件。

<?php echo yoyo_update(); ?>

您需要为路由到初始配置中使用的 Yoyo url 的请求添加此函数调用。

属性

在动态组件中,组件类中的所有公共属性都会自动对视图可用,并在组件更新中进行跟踪。

class HelloWorld extends Component
{
    public $message = 'Hello World!';
}
<div>
    <h1><?php echo $message; ?></h1>
    <!-- Will output "Hello World!" -->
</div>

公共属性应该是以下类型之一:stringintarrayboolean,并且不应包含任何敏感信息,因为它们可以用在组件请求中以保持数据同步。

属性初始化

您可以使用组件的mount方法来初始化属性,该方法在组件实例化后立即运行,在render方法之前。

class HelloWorld extends Component
{
    public $message;

    public function mount()
    {
        $this->message = 'Hello World!';
    }
}

数据绑定

您可以将HTML元素的值与组件公共属性自动绑定或同步。

class HelloWorld extends Component
{
    public $message = 'Hello World!';
}
<div>
    <input yoyo name="message" type="text" value="<?php echo $message; ?>">
    <h1><?php echo $message;?></h1>
</div>

向任何输入元素添加yoyo属性将使其立即变为响应式。任何对输入的更改都会在组件中更新。

默认情况下,元素的自然事件将被用作事件触发器。

  • input、textarea和select元素在改变事件上触发。
  • form元素在提交事件上触发。
  • 所有其他元素在点击事件上触发。

您可以使用yoyo:on指令来修改此行为,该指令接受由逗号分隔的多个事件。

<input yoyo:on="keyup" name="message" type="text" value="<?php echo $message; ?>">

去抖动和节流请求

有几种方法可以限制对组件的更新请求。

delay - 去抖动请求,使其在最后一次触发后的指定时间后才会执行。

<input yoyo:on="keyup delay:300ms" name="message" type="text" value="<?php echo $message; ?>">

throttle 限制请求在指定的时间间隔内最多执行一次。

<input yoyo:on="input throttle:2s" name="message" type="text" value="<?php echo $message; ?>">

changed - 仅当输入值已更改时才执行请求。

<input yoyo:on="keyup delay:300ms changed" name="message" type="text" value="<?php echo $message; ?>">

操作

操作是对Yoyo组件方法发出的请求,以更新(重新渲染)它,作为用户交互或页面事件(点击、鼠标悬停、滚动、加载等)的结果。

如果没有提供显式的操作,则render方法是默认操作。您也可以在组件类中覆盖它以更改模板名称,或者当您需要向模板发送除公共属性外的额外变量时。

public function render() 
{
	return $this->view($this->componentName, ['foo' => 'bar']);
}

要指定操作,请使用具有操作名称值的可用操作指令。

  • yoyo:get
  • yoyo:post
  • yoyo:put
  • yoyo:patch
  • yoyo:delete

例如

class Review extends Component
{
    public Review $review;

    public function helpful()
    {
        $this->review->userFoundHelpful($userId);
    }
}
<div>
    <button yoyo:on="click" yoyo:get="helpful">Found Helpful</button>
</div>

所有组件都会自动监听refresh事件,并触发render操作以刷新组件状态。

传递数据到操作

您可以使用yoyo:vals指令将额外的数据包含在组件更新请求中发送到服务器,该指令接受一个JSON编码的名称-值对列表。

<button yoyo:on="click" yoyo:get="helpful" yoyo:vals='{"reviewId":100}'>Found Helpful</button>

<!-- Or use the encode_vals helper function to pass an array of name-value pairs -->
<button yoyo:on="click" yoyo:get="helpful" yoyo:vals='<?php Yoyo\encode_vals(["reviewId"=> 100]); ?>'>Found Helpful</button>

您还可以使用yoyo:val.name对单个值。破折号命名变量将被自动转换为驼峰命名。

<button yoyo:on="click" yoyo:get="helpful" yoyo:val.review-id="100">Found Helpful</button>

Yoyo会自动跟踪并发送组件公共属性和输入值,以便在每次请求时使用。

class Review extends Component {

	public $reviewId;

	public function helpful()
	{
		// access reviewId via $this->reviewId
	}
}

您还可以使用表达式将额外参数传递给操作作为参数,而无需在组件中将其定义为公共属性。

<button yoyo:get="addToCart(<?php echo $productId; ?>, '<?php echo $style; ?>')">
    Add Todo
</button>

传递给操作的额外参数作为常规参数提供给组件方法。

public function addToCart($productId, $style)
{
    // ...
}

无响应的操作

有时您可能只想使用组件操作来更改数据库并触发事件,而不渲染响应。您可以使用组件的skipRender方法来完成此操作。

public function savePost() 
{
	// Store the post to the database

	// Send event to the browser to close modal, or trigger a notification
	$this->emitSelf('PostSaved');

	// Skip template rendering
	$this->skipRender();
}

视图数据

有时您想向视图发送数据而不声明变量为公共属性。您可以通过在组件中定义一个render方法并传递数据数组作为第二个参数来完成此操作。

public function render() 
{
	return $this->view($this->componentName, ['foo' => 'bar']);
}

然后在模板中访问$foo变量。

您还可以使用任何组件操作中的set方法向组件视图发送数据。例如

public function increment()
{
	$this->set('foo', 'bar');
	// or
	$this->set(['foo' => 'bar']);
}

计算属性

class HelloWorld extends Component
{
	public $message = 'Hello World!';
	
   	// Computed Property
	public function getHelloWorldProperty()
	{
		return $message;
	}

   	// Computed Property with argument
	public function getErrorsProperty($name)
	{
		return [
			'title' => 'Please enter a title',
			'description' => 'Please enter a description',
		][$name] ?? null;
	}
}

现在,您可以从组件类或模板中访问 $this->hello_world

<div>
	<h1><?php echo $this->hello_world ;?></h1>
	<!-- Will output "Hello World!" -->
</div>

带有参数的计算属性表现得像普通类方法,您可以在模板中调用它们

<div>
	<h1><?php echo $this->errors('title') ;?></h1>
	<!-- Will output "Please enter a title" -->
</div>

计算属性的输出在相同的组件请求中缓存,这使得您能够执行复杂的任务,如查询数据库,并且如果属性多次访问则不会重复任务。如果您需要清除计算属性的缓存

// Clear all computed properties, including those with arguments
$this->forgetComputed();

// Clear a single property
$this->forgetComputed($property);

// Clear multiple properties
$this->forgetComputed([$property1, $property2]);

// Clear a single computed property with arguments
$this->forgetComputedWithArgs($property, $arg1, $arg2);

组件属性

Yoyo 可以在请求中持久化和更新变量,而无需显式包含输入元素。

对于匿名组件,可以直接在组件根节点中指定 props,使用变量名称的逗号分隔列表,这允许在不使用组件类的情况下实现计数器

<?php $count = $count ?? 0 ; ?>
<div yoyo:props="count">
	<button yoyo:val.count="<?php echo $count + 1; ?>">+</button> 
    <p><?php echo $count; ?></p>
</div>

通过添加 yoyo:props="count",Yoyo 会自动在每次请求中包含 count 的值。

对于动态组件,不需要使用 yoyo:props 属性,因为我们使用组件类中的受保护方法 $props,该方法有一个变量名称数组。

class Counter extends Component
{
	public $count = 0;
	
	protected $props = ['count'];

    public function increment()
    {
        $this->count++;
    }
}

由于 $count 变量也被定义为公共属性,它已经在模板中可用,并且值通过组件类中的 increment 方法递增,而无需使用 yoyo:val.count

<div>
	<button yoyo:get="increment">+</button>
	<span><?php echo $count; ?></span>
</div>

查询字符串

组件具有在状态变化时自动更新浏览器查询字符串的能力。

class Search extends Component
{
	public $query;
	
	protected $queryString = ['query'];
}

Yoyo 足够智能,可以在当前状态值与属性默认值匹配时自动删除查询字符串。

例如,在分页组件中,不需要在 URL 中出现 ?page=1 查询字符串。

class Posts extends Component
{
	public $page = 1;
	
	protected $queryString = ['page'];
}

加载状态

更新 Yoyo 组件需要向服务器发送 Ajax 请求,并且根据组件执行的操作,响应时间将有所不同。 yoyo:spinning 指令允许您在组件更新时执行各种操作,为最终用户提供视觉指示。

加载状态期间切换元素

在 Yoyo 更新请求开始时显示一个元素,并在更新完成后再次隐藏它

<div>
    <button yoyo:post="submit">Submit</button>

    <div yoyo:spinning>
        Processing your submission...
    </div>
</div>

Yoyo 向页面添加一些 CSS 以自动隐藏带有 yoyo:spinning 指令的元素。

要隐藏在组件更新期间可见的元素,您可以在其中添加 remove 修饰符

<div>
    <button yoyo:post="submit">Submit</button>

    <div yoyo:spinning.remove>
        Text hidden while updating ...
    </div>
</div>

延迟加载状态

某些操作可能更新得很快,在这种情况下显示加载状态可能会分散注意力。 delay 修饰符确保在组件完成更新后 200 毫秒才应用加载状态更改。

<div>
    <button yoyo:post="submit">Submit</button>

    <div yoyo:spinning.delay>
        Processing your submission...
    </div>
</div>

针对特定操作

如果您需要为不同的组件操作切换不同的指示器,可以添加 yoyo:spin-on 指令并传递逗号分隔的操作名称列表。例如

<div>
	<button yoyo:get="edit">Edit</button>

	<button yoyo:get="like">Like</button>

    <div yoyo:spinning yoyo:spin-on="edit">
        Show for edit action
    </div>

    <div yoyo:spinning yoyo:spin-on="like">
        Show for like action
    </div>

    <div yoyo:spinning yoyo:spin-on="edit, like">
        Show for edit and like actions
    </div>

</div>

切换元素 CSS 类

除了切换元素的可见性之外,您还可以在组件更新期间添加特定的 CSS 类。使用 class 修饰符并将空格分隔的类名称作为属性值包含在内

<div>
    <button yoyo:post="submit" yoyo:spinning.class="text-gray-300">
		Submit
	</button>
</div>

您也可以通过添加 remove 修饰符来删除特定的类名称

<div>
    <button yoyo:post="submit" yoyo:spinning.class.remove="bg-blue-200" class="bg-blue-200">
		Submit
	</button>
</div>

切换元素属性

与 CSS 类切换类似,您也可以在组件更新时添加或删除属性。

<div>
    <button yoyo:post="submit" yoyo:spinning.attr="disabled">
		Submit
	</button>
</div>

事件

事件是在同一页面的 Yoyo 组件之间建立通信的绝佳方式,其中一个或多个组件可以监听由另一个组件引发的事件。

事件可以通过使用各种 emit 方法从组件方法或模板中触发。

所有 emit 方法都接受任意数量的参数,这允许发送数据(字符串、数字、数组)到监听器。

向所有 Yoyo 组件发出事件

从组件方法。

public function increment()
{
	$this->count++;
		
	$this->emit('counter-updated', $count);
}

从模板。

<?php $this->emit('counter-updated', $count) ; ?>

向父组件发出事件

在处理嵌套组件时,您可以向父组件发出事件,而不是子组件或同级组件。

$this->emitUp('postWascreated', $arg1, $arg2);

向特定组件发出事件

当您需要使用组件名称(例如 cart)向特定组件发出事件时。

$this->emitTo('cart', 'productAddedToCart', $arg1, $arg2);

使用选择器向元素发射事件

emitTo 方法也支持选择器。当找不到组件时,将使用选择器代替。使用选择器发射事件不支持传递参数。

$this->emitTo('.cart', 'productAddedToCart');
$this->emitTo('#cart', 'productAddedToCart');
$this->emitTo('.post-100', 'saved');

向自身发射事件

当需要在同一组件上发射事件时。

$this->emitSelf('productAddedToCart', $arg1, $arg2);

监听事件

要在 Yoyo 中注册监听器,请使用组件的受保护的属性 $listeners

监听器是一个键-值对,其中键是要监听的事件,值是在组件上调用的方法。如果事件和方法相同,可以省略键。

class Counter extends Component {

	public $message;

	protected $listeners = ['counter-updated' => 'showNewCount'];

	protected function showNewCount($count)
	{
		$this->message = "The new count is: $count";
	}
}

在 JavaScript 中监听事件

Yoyo 允许为组件发射的事件注册事件监听器

<script>
Yoyo.on('productAddedToCart', id => {
	alert('A product was added to the cart with ID:' + id
});
</script>

使用此功能,您可以直接从组件在服务器上的操作通过发射事件并在浏览器上监听它来控制吐司、警告、模态框等。

分发浏览器事件

除了允许组件相互通信外,您还可以直接从组件方法或模板发送浏览器窗口事件

// passing single value
$this->dispatchBrowserEvent('counter-updated', $count);

// Passing an array
$this->dispatchBrowserEvent('counter-updated', ['count' => $count]);

并在页面的任何地方监听该事件

<script>
window.addEventListener('counter-updated', event => {
	// Reading a single value
	alert('Counter is now: ' + event.detail);

	// Reading from an array
	alert('Counter is now: ' + event.detail.count);
})
</script>

重定向

有时您可能希望在 Yoyo 组件内部执行操作后将用户重定向到不同的页面。

class Registration extends Component
{
    public function register()
    {
	// Create the user 

	$this->redirect('/welcome');
    }
}

使用 Blade

您可以使用 Yoyo 与 Laravel 的 Blade 模板引擎一起使用,而无需使用 Laravel。

安装

要开始,请在项目中安装以下包

composer require clickfwd/yoyo
composer require jenssegers/blade

配置

创建一个 Blade 实例并将其设置为 Yoyo 的视图提供者。我们还将 YoyoServiceProvider 添加到 Blade。

此代码应在渲染和更新组件时运行。

<?php

use Clickfwd\Yoyo\Blade\Application;
use Clickfwd\Yoyo\Blade\YoyoServiceProvider;
use Clickfwd\Yoyo\ViewProviders\BladeViewProvider;
use Clickfwd\Yoyo\Yoyo;
use Illuminate\Contracts\Foundation\Application as ApplicationContract;
use Illuminate\Contracts\View\Factory as ViewFactory;
use Illuminate\Support\Fluent;
use Jenssegers\Blade\Blade;

define('APP_PATH', __DIR__);

$yoyo = new Yoyo();

$yoyo->configure([
  'url' => 'yoyo',
  'scriptsPath' => APP_PATH.'/app/resources/assets/js/',
  'namespace' => 'App\\Yoyo\\',
]);

// Create a Blade instance

$app = Application::getInstance();

$app->bind(ApplicationContract::class, Application::class);

// Needed for Blade anonymous components

$app->alias('view', ViewFactory::class);

$app->extend('config', function (array $config) {
    return new Fluent($config);
});

$blade = new Blade(
    [
        APP_PATH.'/resources/views',
        APP_PATH.'/resources/views/yoyo',
        APP_PATH.'/resources/views/components',
    ],
    APP_PATH.'/../cache',
    $app
);

$app->bind('view', function () use ($blade) {
    return $blade;
});

(new YoyoServiceProvider($app))->boot();

// Optionally register Blade components

$blade->compiler()->components([
    // 'button' => 'button',
]);

// Register Blade view provider for Yoyo

$yoyo->registerViewProvider(function() use ($blade) {
    return new BladeViewProvider($blade);
});

加载资源

在以下供应商路径中找到 yoyo.js 并将其复制到您的项目公共资源目录。

/vendor/clickfwd/yoyo/src/assets/js/yoyo.js 

要加载 Blade 模板中所需的脚本,您可以在 <head> 标签中使用 yoyo_scripts 指令

@yoyo_scripts

渲染 Blade 视图

您可以使用 Blade 实例渲染任何 Blade 视图。

$blade = \Clickfwd\Yoyo\Yoyo::getViewProvider()->getProviderInstance();

echo $blade->render('home');

渲染 Yoyo Blade 组件

要在 Blade 视图中渲染 Yoyo 组件,请使用 @yoyo 指令。

@yoyo('search')

更新 Yoyo Blade 组件

要更新 Yoyo 组件在 Yoyo 指定的路由中。

echo (new \Clickfwd\Yoyo\Blade\Yoyo())->update();

内联视图

在处理简单模板时,您可以在组件中没有模板文件的情况下创建组件,而是在组件的 render 方法中返回内联视图。

class HelloWorld extends Component
{
    public $message = 'Hello World!';
}

public function render()
{
	return <<<'yoyo'
		<div>
		    <input yoyo name="message" type="text" value="{{ $message }}">
		    <h1>{{ $message }}</h1>
		</div>		
	yoyo;
}

其他 Blade 功能

Yoyo 实现了几个可以在 Yoyo 组件模板中使用的 Blade 指令。

  • @spinning@endspinning - 检查组件是否正在重新渲染。

     @spinnning
     Component updated
     @endspinning
     
     @spinning($liked == 1)
     Component updated and liked == 1
     @endspinning
  • 所有事件方法都作为指令在 blade 组件中可用

     @emit('eventName', ['foo' => 'bar']);
     @emitUp('eventName', ['foo' => 'bar']);
     @emitSelf('eventName', ['foo' => 'bar']);
     @emitTo('component-name', 'eventName', ['foo' => 'bar']);
  • 计算属性

     class HelloWorld extends Component
     {
         public $message = 'Hello World!';
    
         public function getHelloWorldProperty()
         {
     	    return $message;
         }
     }
     <div>
         <h1>{{ $this->hello_world }}</h1>
         <!-- Will output "Hello World!" -->
     </div>

使用 Twig

您可以使用 Yoyo 与 Symfony 的 Twig 模板引擎一起使用。

安装

要开始,请在项目中安装以下包

composer require clickfwd/yoyo
composer require twig/twig

配置

创建一个 Twig 实例并将其设置为 Yoyo 的视图提供者。我们还将 YoyoTwigExtension 添加到 Twig。

此代码应在渲染和更新组件时运行。

use Clickfwd\Yoyo\Twig\YoyoTwigExtension;
use Clickfwd\Yoyo\ViewProviders\TwigViewProvider;
use Clickfwd\Yoyo\Yoyo;
use Twig\Extension\DebugExtension;

define('APP_PATH', __DIR__);

$yoyo = new Yoyo();

$yoyo->configure([
  'url' => 'yoyo',
  'scriptsPath' => APP_PATH.'/app/resources/assets/js/',
  'namespace' => 'App\\Yoyo\\',
]);

$loader = new \Twig\Loader\FilesystemLoader([
  APP_PATH.'/resources/views',
  APP_PATH.'/resources/views/yoyo',
]);

$twig = new \Twig\Environment($loader, [
  'cache' => APP_PATH.'/../cache',
  'auto_reload' => true,
  // 'debug' => true
]);

// Add Yoyo's Twig Extension

$twig->addExtension(new YoyoTwigExtension());

// Register Twig view provider for Yoyo

$yoyo->registerViewProvider(function() use ($twig) {
  return new TwigViewProvider($twig);
});

加载资源

在以下供应商路径中找到 yoyo.js 并将其复制到您的项目公共资源目录。

/vendor/clickfwd/yoyo/src/assets/js/yoyo.js 

要加载 Twig 模板中所需的脚本,您可以在 <head> 标签中使用 yoyo_scripts 函数

{{ yoyo_scripts() }}

渲染 Twig 视图

您可以使用 Twig 实例渲染任何 Twig 视图。

$twig = \Clickfwd\Yoyo\Yoyo::getViewProvider()->getProviderInstance();

echo $twig->render('home');

渲染 Yoyo Twig 组件

要在 Twig 视图中渲染 Yoyo 组件,请使用 yoyo 函数。

yoyo('search')

更新 Yoyo Twig 组件

要更新 Yoyo 组件在 Yoyo 指定的路由中。

echo (new \Clickfwd\Yoyo\Yoyo())->update();

内联视图

在处理简单模板时,您可以在组件中没有模板文件的情况下创建组件,而是在组件的 render 方法中返回内联视图。

class HelloWorld extends Component
{
    public $message = 'Hello World!';
}

public function render()
{
	return <<<'twig'
		<div>
		    <input yoyo name="message" type="text" value="{{ message }}">
		    <h1>{{ message }}</h1>
		</div>		
	twig;
}

其他 Twig 功能

Yoyo 添加了一些可以在 Yoyo 组件模板中使用的函数和变量。

  • spinning 变量可用于检查组件是否正在重新渲染。

     {% if spinning %}
     Component updated
     {% endif %}
  • 所有事件方法都作为函数在 blade 组件中可用

     {{ emit('eventName', {'foo':'bar'}) }}
     {{ emitUp('eventName', {'foo':'bar'}) }}
     {{ emitSelf('eventName', {'foo':'bar'}) }}
     {{ emitTo('component-name', 'eventName', {'foo':'bar'}) }}
  • 计算属性

     class HelloWorld extends Component
     {
         public $message = 'Hello World!';
    
         public function getHelloWorldProperty()
         {
     	    return $this->message;
         }
     }
     <div>
     	<h1>{{ this.hello_world }}</h1>
     	<!-- Will output "Hello World!" -->
     </div>

许可证

版权所有 © ClickFWD

Yoyo 是开源软件,许可协议为 MIT 许可协议