tekton/components

此包已被废弃,不再维护。未建议替代包。

一个组件系统,可以与gulp-single-file-components一起工作,也可以独立编译文件。

2.3.1 2018-11-17 13:23 UTC

This package is auto-updated.

Last update: 2020-06-09 20:10:47 UTC


README

这是一个PHP组件库,有意构建为模块化,以便可以轻松集成到各种框架中。

安装

composer require tekton/components

JS编译器

如果您希望在构建过程中编译组件并且使用Node.js构建环境,您可以配置gulp-single-file-components来为您完成这项工作。不幸的是,由于该功能已集成到Tekton Components中,该项目不再积极维护。

用法

注册组件

ComponentManager和ComponentCompiler可以分别使用,并配置为提前编译文件并从缓存中加载,或者您可以配置一个编译器,在ComponentManager中自动使用,如果注册了单个文件组件文件(SCF)。

默认情况下,项目包括可以模拟Vue.js组件系统功能的过滤器和标签类。

use Tekton\Components\ComponentManager;
use Tekton\Components\ComponentCompiler;

$cacheDir = __DIR__.'/cache';
$compiler = new ComponentCompiler($cacheDir);
$compiler->registerTags('template', new TemplateTag);
$compiler->registerTags('style', new StyleTag);
$compiler->registerTags('script', new ScriptTag);

$manager = new ComponentManager($compiler);

$manager->register('button.vue');

注册方法接受参数的其他方式如下

// Register by list of components where keys are the name to register
$manager->register([
    'button' => [
        'template' => 'cache/button.html',
        'style' => 'cache/button.css',
        'script' => 'cache/button.js',
    ]
    // ...
]);

// If non-associative array is passed then it must be component files and not
// array of resources. The second argument can optionally be set to specify
// the base directory so that components in sub-dirs don't create naming conflicts
$manager->register([
    'button.vue',        // will be named "button"
    'contact/button.vue' // will be named "contact.button"
    // ...
], __DIR__);

// Register by name and component instance
$manager->register('button', new Component(['template' => 'cache/button.html']));

// Register by component path and optional base path
$manager->register('components/button.vue', 'components/');

// Register component by name and resources array
$manager->register('button', [
    'template' => 'cache/button.html',
    'style' => 'cache/button.css',
    'script' => 'cache/button.js',
]);

您可以通过具有名称和资源的关联数组检索编译器编译的所有组件,或者如果您有一个包含预编译组件的目录,您可以通过将文件扩展名与映射匹配来处理目录内容。

// From the compiler
$components = $compiler->getComponentMap();

// Or
$components = $manager->find('cache/', [
    'template' => ['html', 'php'], // Priority goes from end to beginning
    'scripts' => 'js',
    'style' => 'css',
]); // Passing (bool) true as the third argument registers them directly

$manager->register($components);

例如,如果您只想在开发环境中测试文件更改,并在生产中避免列出文件,而是简单地在每个发布时清除缓存,则可以设置编译器在验证缓存时忽略文件修改时间,因此只有在文件之前未编译时才编译文件。

$compiler->setIgnoreCacheTime(true);

使用组件

要将组件包含在页面中,您只需调用。

$manager->include('button');

button.vue

<template lang="php">
    <div class="button">
        <?php if (true): ?>
            Button
        <?php endif; ?>
    </div>
</template>

<style lang="scss">
    $myColor: #00ff00;

    .button {
        color: $myColor;
    }
</style>

<script>
    alert('component included')
</script>

这样做将简单地渲染模板,CSS和JS需要在您的模板中单独处理,因为不同的框架处理资源的方式有很多。

// Combine all script files and only make one http request
$cacheScripts = $cacheDir.'/components.js';

if (! file_exists($cacheScripts)) {
    $files = $manager->resources('script');
    $combined = concat_files($files);

    file_put_contents($cacheScripts, $combined);
}

echo '<script src="'.$cacheScripts.'"></script>';

// You can validate your combined script by comparing modification time with...
$mtime = $compiler->getLastCacheUpdate();

// Or include every file separately per request and only load those that have
// been included in the page
foreach ($manager->includedResources('script') as $name => $script) {
    echo '<script src="'.$script.'"></script>';
}

过滤器

过滤器在编译时运行在已注册的标签上,并可以使用标签属性确定是否应该运行(例如,在style标签上使用lang="scss")。它们被配置为在标签内容处理前后运行。要为style标签启用SCSS编译,您可以这样做

use Tekton\Components\ComponentManager;
use Tekton\Components\ComponentCompiler;
use Tekton\Components\Filters\ScssFilter;

$styleTag = (new StyleTag)->addPostFilter(new ScssFilter);

$cacheDir = __DIR__.'/cache';
$compiler = new ComponentCompiler($cacheDir);
$compiler->registerTags('style', $styleTag);

$manager = new ComponentManager($compiler);

作用域

为了避免样式和脚本冲突,您可以实现自己的作用域过滤器或使用内置的过滤器。StyleScope 将所有 CSS 规则以 ".component-button" 为前缀,而 TemplateScope 将模板包裹在元素中,并添加组件 ID 和 "component-button" 类。在模板内部,$this 总是指向组件实例,即使您没有使用 TemplateScope 过滤器,也可以轻松访问索引、名称和 ID。

use Tekton\Components\ComponentManager;
use Tekton\Components\ComponentCompiler;

use Tekton\Components\Tags\StyleTag;
use Tekton\Components\Tags\ScriptTag;
use Tekton\Components\Tags\TemplateTag;
use Tekton\Components\Filters\StyleScope;
use Tekton\Components\Filters\ScriptScope;
use Tekton\Components\Filters\TemplateScope;

$cacheDir = __DIR__.DS.'cache';
$compiler = new ComponentCompiler($cacheDir);
$compiler->registerTags('template', (new TemplateTag)->addPostFilter(new TemplateScope));
$compiler->registerTags('style', (new StyleTag)->addPostFilter(new StyleScope));
$compiler->registerTags('script', (new ScriptTag)->addPostFilter(new ScriptScope));

$manager = new ComponentManager($compiler);

模板作用域支持类似 Emmet 的语法(div#myId.myclass[rel=myAttr]),以配置自动创建的容器元素。它仅允许容器、ID、类和属性。这些中的任何一个都可以排除,但必须按此顺序。允许多个类和属性。

<template container="section[rel=home]" src="hero/full-page.html" />

结果将...

<section id="<?= $this->getId() ?>" class="component component-hero" rel="home">
    <!-- contents of hero/full-page.html -->
</section>

为了确保脚本在每个组件中只运行一次,或者如果它们都被编译到一个文件中,您需要一种方法来控制组件脚本仅在包含时执行。ScriptScope 过滤器为此提供了一些额外的辅助方法。这些必须在所有组件都已包含之后运行,因此,如果您正在使用从底部向上解析模板的模板系统,则应在 head 中运行,或者如果您在 body 的页脚中运行。

<!-- first include all the component scripts -->
<script src="cache/compiled-scripts.js"></script>

<script>
    // Pass manager to ScriptScope to create a list of all components included in the page
    <?= ScriptScope::getIncludedComponentsScript($manager); ?>

    // lastly include the script that handles execution
    <?= ScriptScope::getScopeScript(); ?>
</script>

现在脚本标签的内容仅在包含时执行,并且每个组件执行一次。当它执行时,this 被设置为组件的包装元素。名称、选择器(类)和 ID 也会传递,以便您可以在包含多个组件的情况下仅处理当前实例的组件。

您还可以在脚本标签上设置 "singleton" 属性,以确保脚本无论包含多少组件都只执行一次。

自定义渲染器

为了将组件的渲染集成到不同的模板系统中,您很可能需要扩展组件类(实现 ComponentInterface)并更改 ComponentManager 使用的类来自动实例化组件。

// Either set it when creating the ComponentManager
$manager = new ComponentManager($compiler, MyCustomComponent::class);

// Or after
$manager->setComponentClass(MyCustomComponent::class);

许可证

MIT