Components
Edge 组件系统深受 Vue 与 Svelte 等前端框架的启发。它借鉴了 reusability、isolated state、props 和 slots 的概念。
请注意,Edge 是一个后端模板引擎,我们不能用 Edge 复制一些前端生态系统原则。它包括。
- 反应性: 在后端没有反应性的概念。你可以生成 HTML 并通过网络发送它。
- 限定作用域的 CSS: Edge 不是使用 Webpack 这样的前端构建工具来编译的, 因此,它不会为编译和从组件中提取 css 而烦恼。为此,你必须使用现有的前端工具。
创建组件#
组件使用常规 Edge 模板文件表示。例如,你可以使用以下标记创建一个名为 button.edge
的文件。
<button type="{{ type }}">
{{ text }}
</button>
然后将其用作其他模板中的组件。
@!component('button', {
text: 'Login',
type: 'submit'
})
@component
标签总共接受两个参数。一是组件路径(相对于 views 目录),二是组件状态(props)。
注:组件不能访问父模板的状态。但是,它们可以访问模板 [globals]() 和 [locals]()。
Props#
props 作为键值对对象的第二个参数传递给组件。通过使用对象属性名,可以在组件文件中直接访问 prop。例如:
@!component('button', {
text: 'Login',
type: 'submit'
})
然后 button
组件可以访问 text
和 type
属性,如下所示。
<button type="{{ type }}">{{ text }}</button>
$props#
访问 props 的另一种方法是使用 $props
属性。它是 Props 类 的一个实例,并带有一些额外的功能,以使组件编写更容易。
在以下示例中,serializeExcept
方法会将所有道具转换为 HTML 属性,但 text
Prop 除外。
<button {{ $props.serializeExcept(['text']) }}>{{ text }}</button>
@!component('button', {
text: 'Login',
type: 'submit',
class: 'py-2 px-8 text-white bg-gray-800',
})
与 serializeExcept
方法类似,你可以使用 serializeOnly
方法仅序列化选定的道具或使用 serialize
方法将所有 Prop 转换为 HTML 属性。
插槽#
除了 props,组件还可以接受 slots
。slots 是父组件可以为其定义标记的命名插槽。
例如,让我们接受 button
组件的文本作为插槽而不是 prop。
<button type="{{ type }}">
{{{ await $slots.main() }}}
</button>
组件调用者可以如下定义主槽的标记。
@component('button', {
type: 'submit'
})
<i class="fa-icon-lock" />
<span> Login </span>
@end
主插槽#
@component
开始和结束标记之间的内容是主插槽的一部分,除非你将其移动到命名插槽中。
@slot('trigger')
之外的所有内容都是以下示例中主插槽的一部分。
@component('modal')
@slot('trigger')
<a href=""> Show modal </a>
@end
<h1> Modal title </h1>
<p> Modal content </p>
@end
命名插槽#
命名槽允许组件接受多个出口的标记。例如,模态组件可以接受模态标题、正文和操作的标记。
// components/modal.edge 文件
<div>
<header>
{{{ await $slots.header() }}}
</header>
<main>
{{{ await $slots.main() }}}
</main>
<footer>
{{{ await $slots.actions() }}}
</footer>
</div>
父模板可以按如下方式定义它们。
@component('components/modal')
@slot('header')
<h1> Delete post </h1>
@end
@slot('main')
<div>
<p>Are you sure, you want to delete the post</p>
</div>
@end
@slot('actions')
<div class="flex">
<button>Yes, delete it</button>
<button>Cancel</button>
</div>
@end
@end
输出#
插槽作用域#
插槽可以访问定义它们的模板(也称父模板)的状态。
以下是按钮组件的标记
// components/button.edge 文件
@set('title', 'I am a button')
<button>
{{{ await $slots.main() }}}
</button>
父模板正在尝试访问在 component
中定义的 title
属性。
// home.edge 文件
@component('components/button')
<span>{{ title }}</span>
@end
<!-- 输出 -->
<button>
<span>undefined</span>
</button>
你可以将组件中的数据作为参数传递给 slot
方法。
// components/button.edge 文件
@set('title', 'I am a button')
<button>
{{{ await $slots.main({ title }) }}}
</button>
// home.edge 文件
@component('components/button')
@slot('main', scope)
<span>{{ scope.title }}</span>
@end
@end
总结:
- 父模板可以使用 prop 或插槽将数据传递给组件。
- 组件只能将数据作为参数传递给插槽。
向组件树注入数据#
Edge 的数据注入 API 的灵感来自于 Svelte 上下文 API 和 Vue provide/inject API。
目的是简化树内组件之间的通信,但是请注意,这是一个高级 API,只能在你自行创作一组组件并希望它们之间进行透明通信时使用。
基本示例#
让我们从最基本的示例开始,看看实际的注入 API。你可以使用 @inject
标签与组件树共享对象。
// 主题: 组件文件
{{-- Declare a local variable --}}
@set('counter', { value: 0 })
{{-- Inject it to the components tree --}}
@inject({ counter })
{{{ await $slots.main() }}}
由于 @inject
标记通过引用共享对象,因此组件树的任何部分都可以改变其属性,如下所示。
注入的值在 $context
变量中可用。
@component('components/parent')
<p> Value of counter is {{ $context.counter.value }} </p>
{{-- Bump the value by one --}}
@set($context, 'counter.value', $context.counter.value + 1)
<p> Updated value is {{ $context.counter.value }} </p>
@end
作为标签的组件#
Edge 允许你将存储在 ./resources/views/components
目录中的组件作为 Edge 标签引用。
在 resources/views/components/button.edge
文件中创建以下模板。
// 文件名: resources/views/components/button.edge
<button type="{{ type }}">
{{ text }}
</button>
现在,除了使用 @component
标记来引用按钮组件,你也可以将其引用为 @button
标签。
@!button({
type: 'primary',
text: 'Login'
})
你可以使用点符号引用嵌套目录中的组件。例如, ./components/form/input.edge
中存储的文件引用如下:
@!form.input({
type: 'text',
placeholder: 'Enter username'
})
以下是一个对照表,用于了解应用于组件路径以计算标签名称的转换。
模板路径 | 标签名 |
---|---|
form/input.edge | @form.input |
tool_tip.edge | @toolTip |
checkout_form/input.edge | @checkoutForm.input |
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。