193 lines
11 KiB
Markdown
193 lines
11 KiB
Markdown
### 原子化与可组合性
|
||
|
||
每个指令控制DOM的一小部分,您可以组合多个指令来创建丰富、交互式的用户体验。
|
||
|
||
### 兼容现有区块开发工具
|
||
|
||
该API可直接与标准区块构建工具(如[`wp-scripts`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/))配合使用。要使`wp-scripts`正确构建使用交互式API的[脚本模块](https://make.wordpress.org/core/2024/03/04/script-modules-in-6-5/),只需在[`build`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/#build)和[`start`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/#start)脚本中使用`--experimental-modules`标志即可。
|
||
|
||
### 客户端导航
|
||
|
||
交互式API内置了为站点添加客户端导航的基础功能。此功能完全可选,但它使得在无需脱离WordPress渲染系统的情况下创建此类用户体验成为可能。
|
||
|
||
<div class="callout callout-info">
|
||
基于交互式API的全页客户端导航仍在开发中(参见<a href="https://github.com/WordPress/gutenberg/issues/60951">#60951</a>)。但预计所有交互区块都需要使用交互式API来实现全页客户端导航。仅在此情况下,交互式API可能无法完全兼容其他库(如jQuery)。
|
||
</div>
|
||
|
||
该API还能与[视图过渡API](https://developer.chrome.com/docs/web-platform/view-transitions/)完美配合,让开发者轻松实现页面转场动画。
|
||
|
||
## 为何要建立标准?
|
||
|
||
使用交互式API的区块与使用jQuery等其他方案的交互区块可以共存,且所有功能均能正常运作。但交互式API为交互区块带来了独特优势:
|
||
|
||
- **区块间可轻松通信**:采用标准后,区块通信默认即可实现。若不同区块使用不同的前端交互方案,当由不同开发者创建区块时,跨区块通信会变得复杂且几乎无法实现
|
||
- **组合性与兼容性**:您可以组合交互区块,并将其嵌套至具有定义行为的结构中。遵循同一标准确保了它们的完全跨兼容性。若每个区块采用不同交互方案,很可能导致功能冲突
|
||
- **减少浏览器加载量**:若每个插件作者使用不同JS框架,前端将加载更多代码。统一标准可实现代码复用
|
||
- 当页面所有区块采用此标准时,**可启用全站级功能(如客户端导航)**
|
||
|
||
此外,通过建立标准,**WordPress可为开发者承担最大程度的复杂性**——系统将处理创建交互区块所需的大部分工作。
|
||
|
||
_标准所吸纳的复杂性_
|
||
|
||
<img alt="双列对比表展示有无标准时的差异。无标准时区块开发者需处理所有事项;有标准时:完全由标准处理——工具链、水合作用、与WordPress集成、交互部件服务端渲染、区块间通信、前端性能;部分由标准处理——安全性、无障碍访问、最佳实践;开发者负责——区块逻辑。无标准列中所有事项均需开发者承担" width=60% src="https://make.wordpress.core/files/2023/03/standard-graph.png">
|
||
|
||
这种复杂性吸收机制降低了对开发知识的要求,使开发者无需纠结过多技术决策。
|
||
|
||
采用标准后,从其他交互区块学习变得简单,促进了协作与代码复用。最终使开发流程更精简,对经验较少的开发者更友好。
|
||
|
||
### 向后兼容
|
||
|
||
由于交互性 API 与服务器端渲染完美配合,您可以继续使用所有 WordPress API,包括:
|
||
|
||
- **WordPress 过滤器和操作**:您可以继续使用 WordPress 钩子来修改 HTML,甚至修改指令。此外,现有钩子将按预期正常工作。
|
||
- **核心翻译 API**:例如 `__()` 和 `_e()`。您可以用它来翻译 HTML 中的文本(像往常一样),甚至可以在指令的服务器端使用这些 API。
|
||
|
||
### 可选且渐进式采用
|
||
|
||
交互性 API 流程建立在 WordPress 坚实的基础上和模式之上,推动**渐进式增强**。
|
||
|
||
例如,带有指令的块可以与其他(交互式或非交互式)块共存。这意味着如果页面上有其他使用 jQuery 等其他框架的块,所有内容都将按预期工作。
|
||
|
||
<div class="callout callout-warning">
|
||
使用交互性 API 进行全页面客户端导航将是与其他库兼容规则的例外。详情请参阅 <a href="#客户端导航">客户端导航</a>。
|
||
</div>
|
||
|
||
### 声明式与响应式
|
||
|
||
交互性 API 遵循与其他流行 JS 框架类似的方法,通过分离状态、操作和回调并以声明方式定义它们。为什么是声明式?
|
||
|
||
声明式代码描述程序**应该做什么**,而命令式代码描述程序**应该如何做**。使用声明式方法,UI 会自动响应底层数据的变化而更新。使用命令式方法,您必须在数据每次变化时手动更新 UI。比较以下两个代码示例:
|
||
|
||
_命令式代码_
|
||
|
||
```html
|
||
<button id="toggle-button">切换元素</button>
|
||
<p>此元素现在可见!</p>
|
||
<script>
|
||
const button = document.getElementById("toggle-button");
|
||
|
||
button.addEventListener("click", () => {
|
||
const element = document.getElementById("element");
|
||
if(element) {
|
||
element.remove();
|
||
} else {
|
||
const newElement = document.createElement("p");
|
||
newElement.textContent = "此元素可见";
|
||
document.body.appendChild(newElement);
|
||
}
|
||
});
|
||
</script>
|
||
```
|
||
|
||
_声明式代码_
|
||
|
||
这是上面分享的相同用例,但作为使用此新系统的声明式代码示例。JavaScript 逻辑定义在块的 `view.js` 文件中,并在 `render.php` 中将指令添加到标记中。
|
||
|
||
```js
|
||
// view.js 文件
|
||
|
||
import { store, getContext } from "@wordpress/interactivity";
|
||
|
||
store( 'wpmovies', {
|
||
actions: {
|
||
toggle: () => {
|
||
const context = getContext();
|
||
context.isOpen = !context.isOpen;
|
||
},
|
||
},
|
||
});
|
||
```
|
||
|
||
```php
|
||
<!-- Render.php 文件 -->
|
||
|
||
<div
|
||
data-wp-interactive='wpmovies'
|
||
<?php echo wp_interactivity_data_wp_context( array( 'isOpen' => true ) ); ?>
|
||
>
|
||
<button
|
||
data-wp-on--click="actions.toggle"
|
||
data-wp-bind--aria-expanded="context.isOpen"
|
||
aria-controls="p-1"
|
||
>
|
||
切换
|
||
</button>
|
||
|
||
<p id="p-1" data-wp-bind--hidden="!context.isOpen">
|
||
此元素现在可见!
|
||
</p>
|
||
</div>
|
||
```
|
||
|
||
在创建简单的用户体验时,使用命令式代码可能更容易,但随着应用程序变得更加复杂,它会变得困难得多。交互性 API 必须涵盖从最简单到最具挑战性的所有用例。这就是为什么使用指令的声明式方法更适合交互性 API。
|
||
|
||
### 高性能
|
||
|
||
该 API 旨在尽可能高效:
|
||
|
||
- **指令所需的运行时代码仅约 10 KB**,并且只需为所有块加载一次。
|
||
- **脚本加载不会阻塞页面渲染**。
|
||
|
||
### 可扩展
|
||
|
||
指令可以直接从 HTML 中添加、删除或修改。例如,用户可以使用 [`render_block` 过滤器](https://developer.wordpress.org/reference/hooks/render_block/)来修改 HTML 及其行为。
|
||
|
||
# 关于交互性 API
|
||
|
||
交互性 API 是**一套基于声明式代码的[指令系统](#为什么采用指令),用于[为区块添加前端交互功能](#api-目标)**的[标准化方案](#为什么需要标准)。
|
||
|
||
**指令通过特殊属性扩展 HTML**,告知交互性 API 为 DOM 元素附加指定行为甚至进行元素转换。若您熟悉 [Alpine.js](https://alpinejs.dev/),会发现这是类似的实现方式,但本 API 是专为与 WordPress 无缝协作而设计的。
|
||
|
||
## API 目标
|
||
|
||
交互性 API 的主要目标是**为 Gutenberg 区块的前端交互提供标准化且简单的处理方式**。
|
||
|
||
标准化能让**开发者更轻松地创建丰富的交互式用户体验**,无论是简单的计数器或弹窗,还是更复杂的即时页面导航、即时搜索、购物车与结算功能。
|
||
|
||
目前即使不借助交互性 API,这些用户体验在技术上也能实现。但随着用户体验复杂度的提升以及区块间交互的增多,开发者构建和维护网站的难度会大幅增加。他们需要自行解决大量技术挑战。本 API 旨在为这类交互需求提供开箱即用的解决方案。
|
||
|
||
为应对这些挑战,我们为交互性 API 设定了以下要求/目标:
|
||
|
||
- **区块优先与 PHP 优先**:API 必须与 PHP 及当前区块系统良好兼容(包括在 WordPress 中被广泛使用的动态区块),必须支持服务端渲染,且服务端渲染的 HTML 与客户端水合的 HTML 必须完全一致——这对 SEO 和用户体验至关重要
|
||
- **向后兼容**:API 必须兼容 WordPress 钩子机制(例如可修改服务端渲染的 HTML),同时需支持国际化特性并与站点现有 JS 库(如 jQuery)兼容
|
||
- **可选性与渐进式采用**:延续前一点,API 必须保持可选特性,支持渐进式采用——即未使用本 API 的交互区块可与使用本 API 的区块共存
|
||
- **声明式与响应式**:API 需采用声明式代码,监听数据变化,并仅更新依赖该数据的 DOM 部分
|
||
- **高性能**:运行时必须快速轻量,以确保最佳用户体验
|
||
- **可扩展性**:如同 WordPress 始终注重扩展性,新系统必须提供扩展模式以覆盖大多数使用场景
|
||
- **原子化与可组合性**:通过小型可复用部件的组合构建复杂系统,是创建灵活可扩展解决方案的必要条件
|
||
- **兼容现有区块开发工具**:API 必须与现有区块构建工具集成,无需开发者配置额外工具
|
||
|
||
除上述要求外,在任何解决方案之上集成**客户端导航**都应简单高效。客户端导航是实现页面间跳转无需整页刷新的技术,正是网页开发者最迫切需求的用户体验之一。因此该功能必须与新系统保持兼容。
|
||
|
||
## 为什么采用指令?
|
||
|
||
指令是[对各种可行方案深度研究](https://developer.wordpress.org/block-editor/reference-guides/interactivity-api/iapi-faq/#what-approaches-have-been-considered-instead-of-using-directives)的成果。我们发现这种设计能最高效地满足需求。
|
||
|
||
### 区块优先与 PHP 友好
|
||
|
||
本 API 专为区块生态设计,并秉承 WordPress 恪守 Web 标准的历史传统。
|
||
|
||
由于指令以 HTML 属性形式存在,它们天然适合动态区块与 PHP 环境。
|
||
|
||
*动态区块示例*
|
||
```html
|
||
<div
|
||
data-wp-interactive='wpmovies'
|
||
<?php echo wp_interactivity_data_wp_context( array( 'isOpen' => false ) ); ?>
|
||
data-wp-watch="callbacks.logIsOpen"
|
||
>
|
||
<button
|
||
data-wp-on--click="actions.toggle"
|
||
data-wp-bind--aria-expanded="context.isOpen"
|
||
aria-controls="p-1"
|
||
>
|
||
切换
|
||
</button>
|
||
|
||
<p id="p-1" data-wp-bind--hidden="!context.isOpen">
|
||
此元素现已可见!
|
||
</p>
|
||
</div>
|
||
```
|
||
|
||
如您所见,[`data-wp-on--click`](https://developer.wordpress.org/block-editor/reference-guides/interactivity-api/api-reference/#wp-on) 或 [`data-wp-bind--hidden`](https://developer.wordpress.org/block-editor/reference-guides/interactivity-api/api-reference/#wp-bind) 等指令以自定义 HTML 属性形式添加。WordPress 可在服务端处理此 HTML,执行指令逻辑并生成对应标记。 |