跳转到导航 跳转到主要内容
CNB版本
社区版
cnb.cool
国外版
cnb.build
2025/12/18

WebC

本页大纲
Type Value
Eleventy Name webc
File Extension *.webc
npm @11ty/webc and @11ty/eleventy-plugin-webc
GitHub 11ty/webc and 11ty/eleventy-plugin-webc

为什么使用 WebC?

  • 为 Eleventy 带来一流的组件支持。
    • 使用 Web 标准定义的约定将任何 HTML 元素(包括自定义元素)扩展为 HTML。
    • 这意味着使用 WebC 创建的 Web 组件与服务器端渲染兼容(无需重复作者编写的标记)
    • WebC 组件支持渐进增强

性能

  • 创建精简的组件驱动、缓存友好的页面特定 JavaScript 和 CSS 包。用户只需加载渲染该页面所需的代码(或该岛屿的代码)。
    • 为关键组件 CSS 和 JavaScript 轻松配置边界
    • is-land 完美配合,用于 Web 组件激活。
  • 当与 --incremental 一起使用时,获得一流的增量构建(用于页面模板、组件和 Eleventy 布局)
  • 流友好(在边缘流式传输 👀)

与标准兼容

  • 使用 parse5 解析 WebC HTML,就像现代浏览器一样(向 @DasSurma 的 Vite 工作致敬)
  • Shadow DOM 和声明式 Shadow DOM 友好(轻松在 Light DOM 和 Shadow DOM 之间切换组件)

编写

  • 鼓励无怪异模式 HTML 编写(doctype 是可选的)。如果 WebC 遇到怪异模式标记,会抛出一个有用的错误。
  • 轻松限定组件 CSS 的作用域(或使用您自己的作用域工具)。
  • 厌倦了导入组件?使用全局或每页无需导入的组件。
  • 异步友好:所有配置扩展/钩子都默认支持异步。
  • 对于更复杂的模板需求,在 WebC 内部渲染任何现有的 Eleventy 模板语法(Liquid、markdown、Nunjucks 等)。

Resources

安装

注意:Eleventy 中的 WebC 支持包含在核心中!您必须安装官方支持的 Eleventy 插件,并且该插件需要 Eleventy 2.0.0-canary.16或更新版本。

该插件位于 npm 上的 @11ty/eleventy-plugin-webc

npm install @11ty/eleventy-plugin-webc

要在 Eleventy 中添加对 .webc 文件的支持,请在您的 Eleventy 配置文件中添加该插件:

eleventy.config.js
import pluginWebc from "@11ty/eleventy-plugin-webc";

export default function(eleventyConfig) {
eleventyConfig.addPlugin(pluginWebc);
};
const pluginWebc = require("@11ty/eleventy-plugin-webc");

module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(pluginWebc);
};
完整选项列表(显示默认值)
eleventy.config.js
import pluginWebc from "@11ty/eleventy-plugin-webc";

export default function (eleventyConfig) {
eleventyConfig.addPlugin(pluginWebc, {
// 查找无需导入的全局组件的 Glob
//(默认值在 Eleventy WebC v0.7.0 中从 `false` 改变)
components: "\_components/\*_/_.webc",

    	// 添加 Eleventy WebC 转换来处理所有 HTML 输出
    	useTransform: false,

    	// 在 Eleventy WebC 转换中使用的额外全局数据
    	transformData: {},

    	// 传递给 @11ty/eleventy-plugin-bundle 的选项
    	bundlePluginOptions: {},
    });

};
const pluginWebc = require("@11ty/eleventy-plugin-webc");

module.exports = function (eleventyConfig) {
eleventyConfig.addPlugin(pluginWebc, {
// 查找无需导入的全局组件的 Glob
//(默认值在 Eleventy WebC v0.7.0 中从 `false` 改变)
components: "\_components/\*_/_.webc",

    	// 添加 Eleventy WebC 转换来处理所有 HTML 输出
    	useTransform: false,

    	// 在 Eleventy WebC 转换中使用的额外全局数据
    	transformData: {},

    	// 传递给 @11ty/eleventy-plugin-bundle 的选项
    	bundlePluginOptions: {},
    });

};

查看 Bundle 插件的完整选项列表。例如,您可以使用 transforms 数组通过 postcss 修改包内容

语法高亮

因为 WebC 就是 HTML,您可以配置编辑器将 .webc 文件视为 HTML,这应该能正确语法高亮您的 WebC 文件。您选择的编辑器应该有一些关于如何实现这一功能的文档。

用法

在 Eleventy 中使用 WebC 有几种不同的方式:

添加一个新的 .webc 文件

添加插件将为您的 Eleventy 项目启用 .webc 文件支持。只需在您的 Eleventy 输入目录中创建一个新的 .webc HTML 文件,Eleventy 就会为您处理它!值得注意的是,.webc 文件将运行打包器模式下的 WebC,聚合每个单独页面上使用的 CSS 和 JS,以创建该页面上使用的资源包。

WebC 使用 HTML 解析器处理输入文件:在这里使用任何 HTML!

Filename my-page.webc
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8" />
		<title>WebC Example</title>
	</head>
	<body>
		WebC *is* HTML.
	</body>
</html>

非传统的 WebC 用法

使用 Render 插件

使用 Eleventy 内置的 Render 插件 允许您在现有的 Liquid、Nunjucks 或 11ty.js 模板中渲染 WebC。

{% renderTemplate "webc" %}
<my-custom-component></my-custom-component>
{% endrenderTemplate %}
{% renderTemplate "webc" %}
<my-custom-component></my-custom-component>
{% endrenderTemplate %}
export default async function () {
	let content = await this.renderTemplate(
		`<my-custom-component></my-custom-component>`,
		"webc"
	);
	return content;
};
module.exports = async function () {
	let content = await this.renderTemplate(
		`<my-custom-component></my-custom-component>`,
		"webc"
	);
	return content;
};

将 HTML 输入预处理为 WebC

您可以使用配置选项将默认的 HTML 预处理器(从 liquid)更改为 webc。这可能看起来像 htmlTemplateEngine: "webc"。更多关于 Eleventy 文档:HTML 文件的默认模板引擎的信息。

将 HTML 输出后处理为 WebC

这是一个(最后手段?)通用选项,让 WebC 处理项目中的 .html 输出文件(跳过任何 .webc 输入文件以避免重复处理模板)。此功能使用 Eleventy 转换,当您希望在现有项目上快速启动并运行 WebC 时最有用。

转换方法有几个缺点:

  1. 这是在项目中实现 WebC 的构建性能最慢的方法,所以请先尝试其他方法!
  2. WebC Eleventy 转换在打包器模式禁用下运行,这意味着处理 WebC 但不会聚合组件 JS 或 CSS。(支持此增强请求
转换默认是禁用的,您需要使用 useTransform 选项来启用它。
eleventy.config.js
import pluginWebc from "@11ty/eleventy-plugin-webc";

export default function (eleventyConfig) {
eleventyConfig.addPlugin(pluginWebc, {
useTransform: true,
});
};
const pluginWebc = require("@11ty/eleventy-plugin-webc");

module.exports = function (eleventyConfig) {
eleventyConfig.addPlugin(pluginWebc, {
useTransform: true,
});
};

WebC 参考

注意: 所有 webc: 属性都会从渲染的输出 HTML 中移除。

仅 HTML 组件

当组件只有内容 HTML(没有 CSS 或 JavaScript)时,它将在输出 HTML 中忽略宿主组件标签。这使得仅 HTML 组件能够实现零开销 HTML。(您可以使用 webc:keep 选择退出此行为。)

展开查看示例
WebC 组件在这里不受自定义元素名称限制(例如 my-component)的限制。您可以使用 pblockquoteh1img 或任何有效的 HTML 标签名称。
Filename page.webc
<!DOCTYPE html>
<title>WebC Example</title>
<my-component></my-component>
Filename components/my-component.webc
组件不需要根元素,各位。

输出:

Filename _site/page.html
<!DOCTYPE html>
<html>
	<head>
		<title>WebC Example</title>
	</head>
	<body>
		组件不需要根元素,各位。
	</body>
</html>

资源打包

对于不是仅 HTML 的组件(它们确实有 CSS 或 JS),WebC 将在输出标记中包含组件标签(例如 <my-component>)(用于样式或客户端脚本)。(您可以使用 webc:nokeep 选择退出此行为。)

展开查看示例
WebC 组件在这里不受自定义元素名称限制(例如 my-component)的限制。您可以使用 pblockquoteh1img 或任何有效的 HTML 标签名称。
Filename page.webc
<!DOCTYPE html>
<title>WebC Example</title>
<my-component></my-component>
Filename components/my-component.webc
组件不需要根元素,各位。
<style>
	/* 嗨 */
</style>

输出:

Filename _site/page.html
<!DOCTYPE html>
<html>
	<head>
		<title>WebC Example</title>
	</head>
	<body>
		<my-component>组件不需要根元素,各位。</my-component>
	</body>
</html>

Eleventy 在打包器模式下运行 WebC。这意味着当它在组件定义中找到 <style><link rel="stylesheet"><script> 元素时,它们会从输出标记中移除,并且它们的内容会聚集在一起,以便在页面上的资源包中重复使用。更多关于 WebC 中的 CSS 和 JS的信息。(您可以使用 webc:keep 选择退出此行为。)

webc:keep

对于仅 HTML 组件,您可以在宿主组件上使用 webc:keep 来保留标签:

<html-only-component webc:keep></html-only-component>

您也可以使用 webc:keep 选择退出组件定义中单个元素的资源打包

<style webc:keep></style>
<script webc:keep></script>

您也可以使用 webc:keep 来保存 <slot> 以在客户端自定义元素中使用。

webc:nokeep

对于 CSS/JS 组件(不是仅 HTML 组件),您可以在宿主组件上使用 webc:nokeep 来丢弃标签:

<css-js-component webc:nokeep></css-js-component>

webc:import

WebC 将扩展它找到的任何使用已知组件的组件。您也可以使用 webc:import 来内联导入组件定义。此导入路径相对于组件文件路径。WebC 检查循环组件依赖,如果遇到循环依赖会抛出错误。

<any-tag-name webc:import="./components/my-component.webc"></any-tag-name>

您可以直接从已安装的 npm 包导入。Eleventy 将开始为现有插件提供 WebC 组件。语法高亮器(4.2.0 或更新版本)提供了今天可以使用的一个:

<syntax-highlight
	language="js"
	webc:import="npm:@11ty/eleventy-plugin-syntaxhighlight"
>
	function myFunction() { return true; }
</syntax-highlight>

这使用组件标签名称(syntax-highlight)在 node_modules/@11ty/eleventy-plugin-syntaxhighlight/syntax-highlight.webc 处查找 WebC 组件,并将其导入到此节点上使用。这也适用于通过 webc:is 的标签名称覆盖。

webc:if

使用 webc:if 来有条件地渲染元素。接受任意 JavaScript(并且是异步友好的)。与动态属性类似,这也可以访问组件属性和特性。

<div webc:if="true">这将会渲染</div>
<div webc:if="false">这不会渲染</div>
<div webc:if="myAsyncHelper()">如果 helper promise 解析为真值,这将会渲染</div>

您可以使用 webc:type="js" (WebC v0.7.1+) 来使用 JavaScript 进行更复杂的条件逻辑(更多内容请参阅下文)。

webc:elseifwebc:else

webc:if 的相邻兄弟元素可以使用 webc:elseif=""webc:else 进行额外的条件逻辑。

<div webc:if="false">这不会渲染</div>
<!-- 插入注释也可以正常工作 -->
<div webc:elseif="true">这将会渲染</div>
<div webc:else>这不会渲染</div>

webc:for 循环

使用 webc:for 循环遍历数据的 HTML。它适用于对象和任何可迭代对象(String、Array、Map、Set 等)。

语法应该感觉类似于 JavaScript 的 for 语句。

数组(或其他可迭代对象)

<!-- 渲染三个 div 元素 -->
<div webc:for="item of [1, 2, 3]" @text="item"></div>

<!-- 访问循环索引(从零开始) -->
<div webc:for="(item, index) of [1, 2, 3]" @text="index"></div>

<!-- 可以随心所欲地命名这些 -->
<div webc:for="myItem of [1, 2, 3]" @text="myItem"></div>
<div webc:for="(myItem, myIndex) of [1, 2, 3]" @text="myIndex"></div>

<!-- any iterable -->
<div webc:for="item of new Set([1, 2, 3])" @text="item"></div>

对象

注意使用 in 而不是 of

<!-- 渲染两个 div 元素 -->
<div webc:for="key in { a: 1, b: 2 }" @text="key"></div>

<!-- 访问值 -->
<div webc:for="(key, value) in { a: 1, b: 2 }" @text="value"></div>

<!-- 访问循环索引(从零开始) -->
<div webc:for="(key, value, index) in { a: 1, b: 2 }" @text="index"></div>

<!-- 可以随心所欲地命名这些 -->
<div
	webc:for="(myKey, myValue, myIndex) in { a: 1, b: 2 }"
	@text="myIndex"
></div>

<!-- 可以使用 `Object.values` 或 `Object.keys` -->
<div webc:for="value of Object.values({ a: 1, b: 2 })"></div>
<div webc:for="key of Object.keys({ a: 1, b: 2 })"></div>

嵌套 webc:for

循环可以嵌套,但从内循环访问外作用域目前不起作用。更多内容请参见 issue #175

插槽

子内容也可以选择使用 <slot>[slot] 进行预编译。此示例使用的是仅 HTML 组件

Filename page.webc
<my-component></my-component> <my-component>这是默认插槽</my-component>
Filename components/my-component.webc
<p><slot>后备插槽内容</slot></p>

编译为:

<p>后备插槽内容</p>
<p>这是默认插槽</p>

如果您的 WebC 组件想要在编译标记中输出 <slot> 标签(用于客户端 JavaScript),请使用 webc:keep 属性(例如 <slot webc:keep>)。

根据 Web 组件标准约定,如果您的组件文件包含无内容标记(例如空白或只有 <style>/<script>),则隐含 <slot></slot>,并且将自动包含默认插槽内容。如果 WebC 组件文件确实包含内容标记,则作为默认插槽传入的内容需要包含 <slot>

命名插槽

这也适用于命名插槽(例如 <span slot="named-slot">)。

展开查看示例
Filename page.webc
<my-component>
	这是默认插槽。
	<strong slot="named-slot">这是一个命名插槽</strong>
	这也是默认插槽。
</my-component>
Filename components/my-component.webc
<p><slot name="named-slot"></slot></p>

编译为:

<p><strong>这是一个命名插槽。</strong></p>

属性和 webc:root

Filename page.webc
<my-component class="sr-only"></my-component>

在您的组件定义内部,您可以使用 webc:root 向外部宿主组件添加属性:

Filename components/my-component.webc
<template webc:root class="another-class"> 一些组件内容 </template>

classstyle 属性值在宿主组件和 webc:root 元素之间按预期合并

比较 WebC 属性数据类型
  1. 属性:HTML 属性字符串。
  2. 属性:仅服务器端的私有 HTML 属性字符串(不渲染到输出)。
  3. 动态属性和属性:作为 JavaScript 求值(任何数据类型,不仅仅是字符串)。

覆盖宿主组件标签

您可以使用 webc:root="override" 来覆盖宿主组件标签名称!这对于仅 HTML 组件(省略宿主组件标签)不是很有用,但当您的组件有样式/脚本时非常有用。

Filename components/my-component.webc
<button webc:root="override">一些组件内容</button>
<style>
	/* 嗨 */
</style>
  • 以前,上述功能通常通过在元素上同时使用 webc:rootwebc:keep 来完成。

嵌套

值得注意的是,webc:root 也可以嵌套在其他内容内部——它不需要存在于组件定义的顶层。(框架爱好者们喜欢深度嵌套在 div 中的东西,对吧?)

Filename components/my-component.webc
<div>
	<div>
		<template webc:root="override" class="another-class">
			一些组件内容
		</template>
	</div>
</div>

Props(属性)

通过在属性前添加 @ 前缀,将任何属性变为 prop。Props 是仅服务器的"私有"属性,不会出现在输出 HTML 中(它们对 WebC 是私有的)。它们与属性相同,只是从输出 HTML 中过滤掉。

Filename page.webc
<my-component @prop="Hello"></my-component>
Filename components/my-component.webc
<p @text="prop"></p>
<!-- 输出 <p>Hello</p> -->
  • 在 HTML 规范中,属性名称是小写的。带有连字符的属性或属性名称在 JS 中会转换为驼峰命名(例如 <my-component @prop-name="test"> 可以像 @text="propName" 一样使用)。更多信息请参见 issue #71
比较 WebC 属性数据类型
  1. 属性:HTML 属性字符串。
  2. 属性:仅服务器端的私有 HTML 属性字符串(不渲染到输出)。
  3. 动态属性和属性:作为 JavaScript 求值(任何数据类型,不仅仅是字符串)。

动态属性和特性

通过在属性前添加冒号(:)前缀,使任何属性或属性动态化(使用 JavaScript 作为值而不是字符串)。您可以在这里访问宿主组件属性、props 和页面数据!

Filename page.webc
<avatar-image
	src="my-image.jpeg"
	alt="Zach is documenting this project"
	:@dynamic-prop="'hello'"
></avatar-image>
Filename components/avatar-image.webc
<img :src="src" :alt="alt" class="avatar-image" />
  • :@ 动态属性前缀是在 WebC v0.9.0 中添加的。
  • 在 HTML 规范中,属性名称是小写的。带有连字符的属性或属性名称在 JS 中会转换为驼峰命名(例如 <my-component @prop-name="test"> 可以像 @text="propName" 一样使用)。更多信息请参见 #71
  • 目前唯一支持动态值的 webc:* 配置属性是 webc:bucket。更多内容即将推出:#143 #148
比较 WebC 属性数据类型
  1. 属性:HTML 属性字符串。
  2. 属性:仅服务器端的私有 HTML 属性字符串(不渲染到输出)。
  3. 动态属性和属性:作为 JavaScript 求值(任何数据类型,不仅仅是字符串)。

@attributes

您可以使用 @attributes 将所有属性(包括宿主组件上的)渲染到当前节点。

Filename components/avatar-image.webc
<!-- 将渲染所有属性,包括来自宿主组件的 `src` 和 `alt` -->
<img @attributes class="avatar-image" />

您也可以使用此功能将任意对象作为属性渲染(注意使用括号以避免 JavaScript 解析为 block + label):

<img @attributes="({ myattribute: 'myValue'})" />

@html

我们提供了一个特殊的 @html prop 来用自定义 JavaScript 覆盖任何标签内容。

<template @html="'Template HTML'"></template>
<template @html="dataProperty"></template>
<!-- webc:nokeep will replace the outer element -->
<template @html="'Template HTML'" webc:nokeep></template>
  • @html 属性返回的内容将被处理为 WebC——在这里返回任何 WebC 内容!
  • 使用 webc:raw 将阻止结果作为 WebC 处理
  • 使用 @raw 作为 webc:raw @html 的别名
<!-- 不作为 WebC 重新处理(在 Eleventy 布局中有用) -->
<!-- 其中 `myHtmlContent` 是一个保存任意 HTML 字符串的变量 -->
<template @raw="myHtmlContent" webc:nokeep></template>

@raw

@html 中所述,您可以使用 @raw 作为 webc:raw @html 的别名。

@text

我们提供了一个特殊的 @text prop 来用自定义 JavaScript 覆盖任何标签内容。这里返回的整个值将被转义!

<p @text="dataProperty"></p>

<!-- 当 dataProperty 包含 `<p>This is text</p>` 时,这将渲染为: -->
<p>&lt;p&gt;This is text&lt;/p&gt;</p>
<!-- webc:nokeep will replace the outer element -->
<p @text="dataProperty" webc:nokeep></p>
  • @text 属性返回的内容不会被处理为 WebC。

webc:is

将组件重新映射到另一个组件名称。

<div webc:is="my-component"></div>

<!-- equivalent to -->
<my-component></my-component>

webc:scoped

我们包含了一个轻量级机制(webc:scoped)来限定组件 CSS 的作用域。选择器会以一个新的组件类名为前缀。类名基于样式内容的哈希值(用于精美地去除相同组件样式的重复)。

展开查看示例
Filename page.webc
<my-component>Default slot</my-component>

如果您使用 :host,它将被替换为该类选择器。

Filename components/my-component.webc
<style webc:scoped>
	:host {
		color: blue;
	}
	:host:defined {
		color: rebeccapurple;
	}
</style>

这会输出:

<my-component class="wcl2xedjk">Default slot</my-component>

并将以下 CSS 聚合到中:

.wcl2xedjk {
	color: blue;
}
.wcl2xedjk:defined {
	color: rebeccapurple;
}
CSS 打包观点提醒 有些人推荐使用声明式 Shadow DOM 来实现组件样式封装。这是一个很好的方法!但它有两个主要缺点:
  1. 渐进增强的故事需要在关键渲染路径中的内容使用之前获得普遍的浏览器支持
  2. 它需要在组件的每个实例中重复 <style>

请注意这些权衡。并记住您可以在 WebC 中使用两种方法!

webc:scoped="my-prefix"

您也可以为 webc:scoped 指定一个属性值来硬编码自己的组件前缀(例如 <style webc:scoped="my-prefix">)。这允许 CSS 看起来更友好和可读。我们将自动检查组件树中的重复值,如果发生冲突则抛出错误。

使用 JavaScript 设置组件

您现在还可以使用 <script webc:setup> 来运行任意 JavaScript 并为您的组件提供数据和标记。这里声明的任何顶级变量都可作为本地数据在您的组件中使用。

这类似于在 Front Matter 中使用 JavaScript 作为自定义 Eleventy Front Matter 类型,尽管 webc:setup 中的数据作用于组件,并且不会在数据级联中回流。

Filename components/my-component.webc
<script webc:setup>
	const myHtml = "<my-webc-component></my-webc-component>"

	function alwaysBlue() {
		return "blue"
	}
</script>

<div @html="myHtml"></div>
<div @raw="myHtml"></div>
<!-- @raw does not reprocess as WebC -->
<div @html="alwaysBlue()"></div>

适用于 varletconstfunctionArrayObject 解构赋值

使用模板语法生成内容

Eleventy WebC 插件中的自定义转换功能(例如 webc:type)已连接到 Eleventy Render 插件,允许您在 WebC 内部使用现有的 Eleventy 模板语法。

注意: webc:type="11ty" 功能是 Eleventy WebC 插件独有的,在非 Eleventy 独立 WebC 中不可用。

使用 webc:type="11ty"11ty:type 属性来指定有效的模板语法

Filename my-page.webc
---
frontmatterdata: "Hello from Front Matter"
---
<template webc:type="11ty" 11ty:type="liquid,md">
{% assign t = "Liquid in WebC" %}
## {{ t }}

_{{ frontmatterdata }}_
</template>
  • 您在这里完全访问数据级联(注意 frontmatterdata 是在上面 在 front matter 中设置 的)。
  • <template>(或 webc:is="template")节点上的自定义转换返回的内容将被处理为 WebC——在这里返回任何 WebC 内容!

使用 JavaScript 生成内容

您也可以使用 webc:type 转换单个元素内容。除了 webc:type="11ty" 之外,还有另外三种捆绑类型:

  1. webc:type="js"
  2. webc:type="render" (superseded by webc:type="js")
  3. webc:type="css:scoped" (internal for webc:scoped—but overridable!)

JavaScript 渲染函数:webc:type="js"webc:type="render"

在 WebC 中运行任何任意服务器端 JavaScript。输出脚本中执行的最后一条语句的结果。异步友好(返回一个 promise,我们会解析它)。

Filename page.webc
<img
	src="my-image.jpeg"
	alt="An excited Zach is trying to finish this documentation"
/>
Filename components/img.webc
<script webc:type="js" webc:root>
	if (!alt) {
		throw new Error("oh no you didn't")
	}
	;`<img src="${src}" alt="${alt}">`
</script>
Expand to see this example with webc:type="render"
<script webc:type="render">
	export default function () {
		if (!this.alt) {
			throw new Error("oh no you didn't")
		}
		// 免费建议:使用 Eleventy Image 插件返回优化的标记
		return `<img src="${this.src}" alt="${this.alt}">`
	}
</script>

或者使用 JavaScript 渲染函数生成一些 CSS:

Filename page.webc
<style webc:is="add-banner-to-css" @license="MIT licensed">
	p {
		color: rebeccapurple;
	}
</style>
Filename components/add-banner-to-css.webc
<template webc:is="style" webc:root="override">
	<script webc:type="js">
		export default function ({license}) {
			return `/* ${license} */`
		}
	</script>
	<slot></slot>
</template>
Expand to see this example with webc:type="render"
<template webc:is="style" webc:root="override">
	<script webc:type="render">
		export default function () {
			return `/* ${this.license} */`
		}
	</script>
	<slot></slot>
</template>
展开查看另一个使用 webc:type="js" 的更复杂条件示例

注意您也可以使用 webc:if

<script webc:type="js">
	export default function ({src, alt}) {
		if (alt) {
			return `<img src="${src}" alt="${alt}">`
		} else {
			return `<a href="${src}">Your image didn't have an alt so you get this link instead.</a>`
		}
	}
</script>

额外提示:

  • 您可以使用 webc:scoped webc:is="style" webc:type="js"(或 webc:type="render")来使用 JavaScript 生成作用域 CSS!更多信息请参见 webc:scoped
  • 您在渲染函数中可以访问组件属性和 props(这在另一节中介绍!)。
  • 使用 webc:type="js" 具有隐含的 webc:is="template" 来返回将被重新处理为 WebC (HTML) 的内容。您可以使用自己的 webc:is 属性来覆盖此项以生成不同的标签(例如 webc:is="script"webc:is="style")。
  • 使用 webc:type="js" 具有隐含的 webc:nokeep 来跳过输出外部节点。您可以添加 webc:keep 来覆盖此行为。

JavaScript 渲染函数的额外数据

  • webc.attributes: an object literal representing the current element's attributes.
  • webc.renderAttributes: a method to render public attributes to a string.
  • webc.filterPublicAttributes: 一个过滤 webc.attributes 的方法,返回仅包含公开属性的对象。用法:webc.filterPublicAttributes(webc.attributes)
  • webc.escapeText: 编码 HTML 文本中所有需要转义的字符(通过 entities)
  • webc.escapeAttribute: 编码 HTML 属性中所有需要转义的字符(通过 entities)

阅读更多关于 Issue #104 的信息。

Expand to see an img component example

可以想象一个这样的 <img> 组件定义,它正确地合并和重用所有宿主组件属性:

Filename components/img.webc
<script webc:type="js" webc:root="override">
	;`<img ${webc.renderAttributes(webc.attributes)}>`
</script>

webc:raw

使用 webc:raw 来选择不对当前节点的所有子内容进行 WebC 模板处理。值得注意的是,当前节点的属性将被处理。这与 <template> 配合得很好!

Filename components/my-component.webc
<template webc:raw>
	别把我包含进去。
	<style>
		p {
			color: rebeccapurple;
		}
	</style>
</template>

webc:ignore

使用 webc:ignore 来完全忽略一个节点,不处理或输出任何相关内容。适用于服务器端注释或组件文档。

Filename components/my-component.webc
<template webc:ignore>
	这是您可能使用此组件的方式:

	<my-component>Nothing in here will be processed</my-component>
</template>

仅服务端注释

与将显示在渲染输出中的 HTML 注释不同,您可以在开头/结尾添加一个或多个破折号来告诉 WebC 从输出中剥离此内容。非常适合服务器端注释。

Filename components/my-component.webc
<!--- WebC will remove this --->
<!-- 这不会*被*移除并且会渲染到输出中 -->
<!------- WebC will remove this, too ------->

自定义转换

此插件开箱即用地提供了一些转换:webc:type="js", webc:type="render", webc:type="css:scoped", 和 webc:type="11ty"

然而,在 Eleventy WebC 插件中,直接向 WebC 添加您自己的webc:type 自定义转换 尚不可用!如果这是大家希望看到添加的功能,请告诉我们

请注意您可以添加自己的自定义模板引擎,这将通过 webc:type="11ty" 提供(例如 <style webc:type="11ty" 11ty:type="sass">)。

辅助函数

WebC 帮助器 是可在动态属性、@html@raw 和渲染函数中使用的 JavaScript 函数。

Eleventy 提供的辅助函数

Eleventy WebC 包含了 JavaScript 模板函数通用过滤器 作为 WebC 帮助器自动提供。

这包括 url, slugify, log 和其他

<!-- Use the  Eleventy provided `url` universal filter -->
<a :href="url('/local-path/')">My Link</a>

提供自己的辅助函数

eleventy.config.js
export default function (eleventyConfig) {
// via Universal Filter
eleventyConfig.addFilter("alwaysRed", () => "Red");

    // or via JavaScript Template Function directly
    eleventyConfig.addJavaScriptFunction("alwaysBlue", () => "Blue");

    // Don't forget to add the WebC plugin in your config file too!

};
module.exports = function (eleventyConfig) {
// via Universal Filter
eleventyConfig.addFilter("alwaysRed", () => "Red");

    // or via JavaScript Template Function directly
    eleventyConfig.addJavaScriptFunction("alwaysBlue", () => "Blue");

    // Don't forget to add the WebC plugin in your config file too!

};
<div @html="alwaysRed()"></div>
<div @html="alwaysBlue()"></div>

<!-- 渲染为: -->
<div>Red</div>
<div>Blue</div>

细节和限制

空元素

自定义元素(根据规范)不被支持作为空元素:它们需要开始和结束标签。

实际上,这意味着 WebC 组件不能是自闭合的。您可以使用 webc:is 来解决此限制(例如 <img webc:is="my-component">)。

<head> Components

使用 HTML 解析器与自定义元素时有一些问题。值得注意的是,解析器试图强制将 <head> 中的自定义元素子元素移动到 <body> 中。要解决此限制,请使用 webc:is

Expand for a few example workarounds
<head webc:is="my-custom-head">
	<!-- 这是插槽内容,是的,您也可以在这里使用命名插槽 -->
</head>
<head>
	<!-- <my-custom-head> is not allowed here but
			 <meta webc:is="my-custom-head> is -->
	<meta webc:is="my-custom-head" />
	<title webc:is="my-custom-title">Default Title</title>
</head>

<table> Components

由于 WebC 使用 parse5 库,所有要处理的 WebC 文件都会像网络浏览器解析它们一样进行解析和标记化。因此,将 <table> 标签放在自定义 WebC 元素中,并将其 <tr><td> 标签放在插槽中以插入到表格中,会导致 <tr><td> 元素在初始解析时被移除,表格的所有内部内容将被放置为其兄弟元素。这是由于 parse5 库认为 <tr><td> 标签是孤立的。

要解决此限制,请对 <table>, <tr>, 和 <td> 元素使用 webc:is

Expand for an example workaround

上述示例假设存在 _includes/my-layout.webc(一个 Eleventy 布局)。

Filename _includes/my-layout.webc
...
<my-table>
	<x webc:is="tr">
		<x webc:is="td"> My Table Content </x>
	</x>
</my-table>
...
Filename components/my-table.webc
<x webc:is="table">
	<slot></slot>
</x>

渲染模式

Eleventy 中有两种不同的渲染模式:pagecomponent。我们尝试根据您提供的标记来猜测您想要的渲染模式。page 渲染模式用于渲染完整的 HTML 页面。component 渲染模式用于 HTML 片段。大多数情况下您不需要担心这种区别,但为了文档的完整性,这里包含了它。

  • page 在标记以 <!doctype(或 <!DOCTYPE)或 <html 开头时使用(WebC 强制无怪异模式解析)。
  • 否则使用 component

与 HTML 解析的差异

WebC 处理 <template><noscript> 标签内部的内容。HTML 解析器将这些视为纯文本。

Eleventy + WebC 功能

Front Matter

Eleventy 中的 WebC 自动适用于 front matter 的标准 Eleventy 约定(尽管 Eleventy 中的 front matter 是可选的)。

Filename with-front-matter.webc
---
layout: "my-layout.webc"
---
WebC *is* HTML.
展开查看 my-layout.webc 示例

上述示例假设存在 _includes/my-layout.webc(一个 Eleventy 布局)。

Filename _includes/my-layout.webc
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8" />
		<title>WebC Example</title>
	</head>
	<body @raw="content"></body>
</html>
  • 更多关于 WebC 属性的信息:@raw@html

重要提示:front matter(根据标准 Eleventy 约定)仅在页面级模板(输入目录中的 .webc 文件)中受支持,而不在组件中(见下文)。

定义组件

组件是 WebC 的 魔法,在 WebC 中有几种定义组件的方法:

  1. 使用在配置文件中指定的全局无需导入组件。
  2. 在数据级联中的目录或模板级别指定无需导入组件的 glob。
  3. 您可以在组件内部使用 webc:import 来直接导入另一个组件。
值得注意的是,WebC 组件可以有任何有效的 HTML 标签名称!它们不受自定义元素相同的命名限制(要求名称中有连字符)的限制。

全局无需导入组件

使用在 Eleventy 配置文件中传递给 addPlugin 的选项中的 components 属性来指定可在任何页面中使用的项目范围的 WebC 组件文件。

我们接受:

  • 字符串(文件路径或 glob)
  • 数组(文件路径或 glob 数组)
  • npm: 前缀别名
eleventy.config.js
import pluginWebc from "@11ty/eleventy-plugin-webc";

export default function (eleventyConfig) {
eleventyConfig.addPlugin(pluginWebc, {
// 查找无需导入的全局组件的 Glob
// 此路径相对于项目根目录!
// 显示默认值:
components: "\_components/\*_/_.webc",

    	// or an Array (Eleventy WebC v0.9.2+)
    	components: [
    		"_components/**/*.webc",
    		"npm:@11ty/is-land/*.webc",
    		"npm:@11ty/eleventy-plugin-syntaxhighlight/*.webc",
    	],
    });

};
const pluginWebc = require("@11ty/eleventy-plugin-webc");

module.exports = function (eleventyConfig) {
eleventyConfig.addPlugin(pluginWebc, {
// 查找无需导入的全局组件的 Glob
// 此路径相对于项目根目录!
// 显示默认值:
components: "\_components/\*_/_.webc",

    	// or an Array (Eleventy WebC v0.9.2+)
    	components: [
    		"_components/**/*.webc",
    		"npm:@11ty/is-land/*.webc",
    		"npm:@11ty/eleventy-plugin-syntaxhighlight/*.webc",
    	],
    });

};

值得注意的是,components 的路径是相对于您的项目根目录(不是您的项目的 input 目录)。

在 glob 中找到的组件文件名决定了您项目中使用的全局标签名(例如,_components/my-component.webc 将让您能够使用 <my-component>)。

在 Front Matter 中声明组件

您也可以在 front matter 中使用和配置特定组件(或者,通过数据级联的任何部分——作用于文件夹或模板),通过将 glob(或 glob 数组)分配给 webc.components 属性:

Filename my-directory/my-page.webc
---
layout: "my-layout.webc"
webc:
  components: "./webc/*.webc"
---

<my-webc-component>WebC *is* HTML.</my-webc-component>
WARNING

默认情况下,这些路径是相对于模板文件的。如果您要在应用于多个子文件夹深度的目录数据文件中的数据级联中设置此选项,最好:

  1. 使用全局无需导入组件选项。
  2. 使用 ~/ 作为前缀(例如 ~/my-directory/webc/*.webc)来别名到项目的根目录。

官方 WebC 组件

以下插件为您的项目提供官方 WebC 组件:

  • @11ty/is-land 提供 <is-land>
  • @11ty/eleventy-plugin-syntaxhighlight 提供 <syntax-highlight>
    • 示例:<syntax-highlight language="js" webc:import="npm:@11ty/eleventy-plugin-syntaxhighlight">
    • 更多信息请参见语法高亮插件
  • @11ty/eleventy-img 提供 <eleventy-image>
    • 示例:<img webc:is="eleventy-image" webc:import="npm:@11ty/eleventy-img">
    • 更多信息请参见图像 WebC 组件

CSS 和 JS(打包器模式)

Eleventy WebC 将打包任何特定页面的资源(页面上组件使用的 CSS 和 JS)。当组件使用 <script><script src><style><link rel="stylesheet"> 时,这些资源会自动汇总。您可以使用此功能实现组件驱动的关键 CSS。

声明式 Shadow DOM 说明:声明式阴影根 模板(<template shadowrootmode> 或已弃用的 <template shadowroot>)内的元素保持原样且不打包
Filename _components/my-webc-component.webc
<style>
	/* 这是组件 CSS */
</style>
<script>
	/* 这是组件 JS */
</script>

<!-- Local file references work too -->
<link rel="stylesheet" href="my-file.css" />
<script src="my-file.js"></script>

如上所示,当 URL 指向文件系统上的文件时,这也包括 <link rel="stylesheet"><script src>尚不支持远程 URL 源)。

您可以使用 webc:keep 按元素选择退出打包。

Filename _includes/layout.webc
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8" />
		<title>WebC Example</title>

		<!-- inline bundles -->
		<style @raw="getBundle('css')" webc:keep></style>
		<script @raw="getBundle('js')" webc:keep></script>

		<!-- or write your bundle to a file -->
		<link rel="stylesheet" :href="getBundleFileUrl('css')" webc:keep />
		<script :src="getBundleFileUrl('js')" webc:keep></script>
	</head>
	<body @raw="content"></body>
</html>
  • Eleventy WebC 在后台使用Bundle 插件来实现打包。现在可以分别使用 getBundle('css')getBundle('js') 来代替 getCss(page.url)getJs(page.url)
  • 在您的布局文件中,<style><script> 上需要 webc:keep 来防止重新打包这些包。
  • getCssgetJs 辅助函数现在可以无限制地在所有 WebC 模板中使用。以前的版本要求它们在 Eleventy 布局 文件中使用。
  • @raw 曾经是。以前的版本可以使用 webc:raw @html

包代码顺序

这些包中代码的顺序由组件的依赖关系决定,从最具体到最不具体!

展开查看示例

假设我们有一个使用 header.webc 组件的 index.webc 页面。

Filename index.webc
<style>
	/* index.webc */
</style>
<header></header>
Filename _components/header.webc
<style>
	/* header.webc */
</style>

CSS 包将看起来像这样:

/* header.webc */
/* index.webc */

在其他模板引擎中访问打包文件

您也可以在其他模板类型中访问这些包(.html.liquid 等)。

Eleventy WebC 在后台使用 Bundle 插件来实现打包。此插件提供 getBundlegetBundleFileUrl 通用短代码,可在任何模板类型中使用(包括上面显示的 WebC)。

WebC v0.8.0 及更早版本:查看已弃用(但为了向后兼容仍然保留)的用于包输出的 webcGetCsswebcGetJs 通用过滤器。
Filename _includes/layout.html
<style>{{ page.url | webcGetCss | safe }}</style>
<script>{{ page.url | webcGetJs | safe }}</script>
<!-- write to a file -->
<link rel="stylesheet" href="{% getBundleFileUrl "css" %}">
Filename _includes/layout.liquid
<style>{{ page.url | webcGetCss }}</style>
<script>{{ page.url | webcGetJs }}</script>

资源分桶

这里有一个额外的打包层,您可以使用它,我们称之为分桶。组件可以使用 webc:bucket 输出到任何任意的桶名称。

在这个组件中,我们有输出到两个独立桶的组件代码:

Filename _components/my-webc-component.webc
<style>
	/* 此 CSS 被放入默认桶中 */
</style>
<script>
	/* 此 JS 被放入默认桶中 */
</script>
<style webc:bucket="defer">
	/* 此 CSS 被放入 `defer` 桶中 */
</style>
<script webc:bucket="defer">
	/* 此 JS 被放入 `defer` 桶中 */
</script>

<my-webc-component> 在页面上使用时,它将资源滚动到页面特定的 CSS 和 JavaScript 桶包中。

然后您可以在页面的任何位置输出这些桶包,如下所示(这里我们使用 Eleventy 布局文件):

Filename _includes/layout.webc
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8" />
		<title>WebC Example</title>
		<!-- Default bucket -->
		<style @raw="getBundle('css')" webc:keep></style>
		<script @raw="getBundle('js')" webc:keep></script>
	</head>
	<body>
		<template @raw="content" webc:nokeep></template>

		<!-- `defer` bucket -->
		<style @raw="getBundle('css', 'defer')" webc:keep></style>
		<script @raw="getBundle('js', 'defer')" webc:keep></script>
	</body>
</html>
  • 在布局文件中,<style><script> 上需要 webc:keep 来防止重新打包这些包。
  • :webc:bucket(动态属性)支持通过 JavaScript 设置此值。#120

级联资源桶

Additionally webc:bucket can be added to any tag and will cascade to all child content.

考虑这个 WebC 页面:

Filename index.webc
<!-- 具有隐含的 webc:bucket="default" -->
<my-component></my-component>

<div webc:bucket="defer">
	<!-- 这些每个都有 webc:bucket="defer" -->
	<!-- (也包括内部的任何嵌套组件) -->
	<footnote-references></footnote-references>

	<my-footer></my-footer>
</div>

设置 webc:bucket 现在会级联到所有子元素,就像它们每个都被单独分配了 webc:bucket="defer" 一样。这些组件中使用的所有资源现在将被汇总到 defer 桶中。

冲突和提升

当组件在多个不同的桶中使用时会发生什么?

Filename index.webc
<!-- 具有隐含的 webc:bucket="default" -->
<my-component></my-component>

<div webc:bucket="defer">
	<my-component></my-component>
</div>

当出现重复和冲突时,WebC 会将组件代码提升到最近的共享桶。在上面的例子中,<my-component> 的 CSS 和 JS 将在 default 桶中加载,并且只在 default 桶中加载。

is-land 一起使用

您也可以开箱即用地使用 Eleventy 的is-land 组件进行 Web 组件水合

在组件级别,组件可以声明自己的 is-land 加载条件。

Filename index.webc
<is-land on:visible webc:import="npm:@11ty/is-land">
	<template data-island>
		<!-- CSS -->
		<style webc:keep>
			/* 此 CSS 在:visible 时适用 */
		</style>
		<link rel="stylesheet" href="arbitrary.css" webc:keep />

		<!-- JS -->
		<script type="module" webc:keep>
			console.log("此 JavaScript 在:visible 时运行")
		</script>
		<script type="module" src="arbitrary.js" webc:keep></script>
	</template>
</is-land>

来自社区

×2 个资源通过 11tybundle.devFavicon for avatar.w3c.cool/https%3A%2F%2Fwww.bobmonsour.com%2FBob Monsour 整理。


其他页面在 Template Languages