利用WordPress Interactivity API解锁新的可能性

利用WordPress Interactivity API解锁新的可能性

文章目录

  • 使用交互API之前需要准备什么
  • 什么是交互API?
  • 交互式区块的结构
  • package.json
  • block.json
  • render.php
  • view.js
  • 交互API指令
  • 全局状态、局部上下文和派生状态
  • 全局状态
  • 本地上下文
  • 派生状态
  • 动作和回调
  • 如何构建交互式模块
  • edit.js文件
  • render.php文件
  • view.js文件
  • 小结

利用WordPress Interactivity API解锁新的可能性

在本博客之前的文章中,我们从多个角度探讨了 WordPress 区块开发。我们研究了静态区块动态区块的开发,并扩展了核心区块的功能。然而,我们目前采用的方法本质上只能创建无法实时响应用户交互的标准区块。简而言之,这些区块是不交互式的。

在本文中,我们将探索一种全新的区块开发方法,借助强大的全新 WordPress API——WordPress Interactivity API,我们将能够创建交互式区块。该 API 在 WordPress 6.5 中引入,使您能够创建可实时响应用户交互的区块,从而打造丰富的用户体验,让您的网站更具吸引力、动态性和互动性。

内容丰富,但在开始之前,让我们先来看看一些基本要求!

使用交互API之前需要准备什么

由于交互 API 基于 React,您至少需要具备服务器端 JavaScript 和 React 的基础知识,以及 npm 和 npx 等构建工具的使用经验。此外,您还需要深入了解 WordPress 开发Gutenberg 区块编辑器

掌握必要的技能后,您需要一个本地开发环境,以便快速轻松地启动 WordPress 网站。我们适用类似 DevKinsta 的工具,这是一款专为 WordPress 设计的本地开发套件。使用 DevKinsta,您只需点击几下即可设置一个新的本地 WordPress 网站,并进行详细的自定义。

在 DevKinsta 中创建新的 WordPress 项目时,您可以设置以下选项:

  • 顶级域名:默认 .local
  • PHP 版本
  • 数据库名称
  • 启用 HTTPS
  • WordPress 详细信息
  • WordPress 自动更新
  • 多站点

此外,您还可以从备份导入现有的 MyKinsta 网站。

在 DevKinsta 中配置本地网站

在 DevKinsta 中配置本地网站

什么是交互API?

交互 API 是 WordPress 原生 API,它允许您为 Gutenberg 区块添加交互功能,进而为 WordPress 网站上的文章和页面添加交互功能。它是一个轻量级、现代化的解决方案,采用声明式方法来管理用户交互。

从头开始创建交互式区块需要高级 PHP 和服务器端 JavaScript 开发技能。但是,您无需在每个新项目中都重复造轮子,因为 WordPress 提供了一个用于创建交互式区块的模板

npx @wordpress/create-block --template @wordpress/create-block-interactive-template

此模板包含搭建交互式模块所需的一切,包括两个可供您参考的示例:一个用于切换当前主题的按钮和一个用于展开/折叠段落的按钮。

要开始使用,请打开您常用的命令行工具,导航到本地 WordPress 安装目录下的 Plugins 文件夹,然后输入以下命令:

npx @wordpress/create-block your-interactive-block --template @wordpress/create-block-interactive-template

请稍等片刻,待安装完成后,使用您常用的代码编辑器打开项目文件夹。我们推荐使用 Visual Studio Code,但您也可以使用任何您用起来最顺手的编辑器。

交互式区块

此交互式区块项目由 @wordpress/create-block-interactive-template 提供。

在命令行中,导航到新插件的文件夹,并使用以下命令启动开发服务器

npm start

从现在开始,您对模块所做的任何更改都将在 WordPress 中实时显示。

接下来,在 WordPress 管理后台,导航至“Plugins”页面,并激活您刚刚创建的“Interactivity API”插件。创建一个新文章或页面,然后在模块插入器中搜索您的交互式区块,并将其添加到您的内容中。保存文章并在前端预览。您将看到一个包含两个按钮的黄色模块。第一个按钮用于更改模块的背景颜色,第二个按钮用于显示或隐藏段落内容。

交互式区块示例

 @wordpress/create-block-interactive-template 提供的交互式区块示例。

现在您已经有了可以参考的插件,本文涵盖的主题也已包含在内,我们可以继续深入探索交互式区块。

交互式区块的结构

交互式区块的结构与传统区块相同。您仍然需要 package.jsonblock.jsonedit.jsstyle.scss 文件。此外,您还需要 render.php 文件用于服务器端渲染,以及 view.js 文件用于处理前端交互。

让我们通过分析初始项目的各个文件来了解交互式区块的具体组成部分。

package.json

package.json 文件用于 Node 项目中,用于标识您的项目、管理脚本以及在开发过程中管理和安装依赖项。

以下是 create-block-interactive-template 提供的交互式区块的 package.json 文件:

{
"name": "your-interactive-block",
"version": "0.1.0",
"description": "An interactive block with the Interactivity API.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
"main": "build/index.js",
"scripts": {
"build": "wp-scripts build --experimental-modules",
"format": "wp-scripts format",
"lint:css": "wp-scripts lint-style",
"lint:js": "wp-scripts lint-js",
"packages-update": "wp-scripts packages-update",
"plugin-zip": "wp-scripts plugin-zip",
"start": "wp-scripts start --experimental-modules"
},
"dependencies": {
"@wordpress/interactivity": "latest"
},
"files": [
"[^.]*"
],
"devDependencies": {
"@wordpress/scripts": "^30.24.0"
}
}

这里 scripts 和 dependencies 部分尤为重要。

  • build:将源代码编译成用于生产环境的 JavaScript。--experimental-modules 选项启用对 WordPress 脚本模块的支持。
  • start:启动开发服务器。请注意,这里再次指定了 --experimental-modules 选项。
  • dependencies:包含运行时依赖项以及最新的 Interactivity API 包。

block.json

block.json 文件是 Gutenberg 区块的清单文件。它指定要加载的元数据、媒体、脚本和样式。默认情况下,create-block-interactive-template 会生成以下 block.json 文件:

{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "create-block/your-interactive-block",
"version": "0.1.0",
"title": "Your Interactive Block",
"category": "widgets",
"icon": "media-interactive",
"description": "An interactive block with the Interactivity API.",
"example": {},
"supports": {
"interactivity": true
},
"textdomain": "your-interactive-block",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"render": "file:./render.php",
"viewScriptModule": "file:./view.js"
}

以下字段对于交互式区块至关重要:

  • apiVersion3 是区块 API 的最新版本,支持最新的区块功能,例如脚本模块。
  • supports:指定区块支持的功能。 "interactivity": true  表示支持交互式 API。
  • render:指定负责前端渲染的 PHP 文件。您可以在此文件中添加使区块具有交互性的指令。
  • viewScriptModule:指定包含交互逻辑的 JavaScript 文件。此文件仅在前端加载,并且仅当页面包含交互式区块时才会加载。

render.php

render.php 文件用于构建动态区块的标记。要使您的区块具有交互性,您需要添加属性以使区块的 DOM 元素具有交互性。

初始项目中的 render.php 文件如下所示:

<?php
/**
* PHP file to use when rendering the block type on the server to show on the front end.
*
* The following variables are exposed to the file:
*     $attributes (array): The block attributes.
*     $content (string): The block default content.
*     $block (WP_Block): The block instance.
*
* @see https://github.com/WordPress/gutenberg/blob/trunk/docs/reference-guides/block-api/block-metadata.md#render
*/
// Generates a unique id for aria-controls.
$unique_id = wp_unique_id( 'p-' );
// Adds the global state.
wp_interactivity_state(
'create-block',
array(
'isDark'    => false,
'darkText'  => esc_html__( 'Switch to Light', 'your-interactive-block' ),
'lightText' => esc_html__( 'Switch to Dark', 'your-interactive-block' ),
'themeText'	=> esc_html__( 'Switch to Dark', 'your-interactive-block' ),
)
);
?>
<div
<?php echo get_block_wrapper_attributes(); ?>
data-wp-interactive="create-block"
<?php echo wp_interactivity_data_wp_context( array( 'isOpen' => false ) ); ?>
data-wp-watch="callbacks.logIsOpen"
data-wp-class--dark-theme="state.isDark"
>
<button
data-wp-on--click="actions.toggleTheme"
data-wp-text="state.themeText"
></button>
<button
data-wp-on--click="actions.toggleOpen"
data-wp-bind--aria-expanded="context.isOpen"
aria-controls="<?php echo esc_attr( $unique_id ); ?>"
>
<?php esc_html_e( 'Toggle', 'your-interactive-block' ); ?>
</button>
<p
id="<?php echo esc_attr( $unique_id ); ?>"
data-wp-bind--hidden="!context.isOpen"
>
<?php
esc_html_e( 'Your Interactive Block - hello from an interactive block!', 'your-interactive-block' );
?>
</p>
</div>

以下是这段代码的功能:

  • wp_interactivity_state:获取和/或设置 Interactivity API 存储的初始全局状态
  • data-wp-interactive:在 DOM 元素及其子元素上启用 Interactivity API。其值必须是您的插件或区块的唯一命名空间。
  • wp_interactivity_data_wp_context():生成 data-wp-context 指令,该指令为特定的 HTML 节点及其子元素提供本地状态
  • data-wp-watch:在节点创建时以及状态或上下文发生更改时运行回调函数
  • data-wp-class--dark-theme:向 HTML 元素添加或移除 dark-theme 类。
  • data-wp-on--click:在点击事件发生时同步运行代码
  • data-wp-text:设置 HTML 元素的内部文本
  • data-wp-bind--aria-expanded 和 data-wp-bind--hidden:根据布尔值或字符串值,为相应的元素设置 HTML 属性aria-expandedhidden)。

view.js

此文件定义了包含区块行为所需逻辑和数据的 Store,包括状态、操作和回调。

以下是启动项目生成的 view.js 文件:

/**
* WordPress dependencies
*/
import { store, getContext } from '@wordpress/interactivity';
const { state } = store( 'create-block', {
state: {
get themeText() {
return state.isDark ? state.darkText : state.lightText;
},
},
actions: {
toggleOpen() {
const context = getContext();
context.isOpen = ! context.isOpen;
},
toggleTheme() {
state.isDark = ! state.isDark;
},
},
callbacks: {
logIsOpen: () => {
const { isOpen } = getContext();
// Log the value of `isOpen` each time it changes.
console.log( `Is open: ${ isOpen }` );
},
},
} );
  • store:用于创建和注册代码块全局状态和逻辑的主要函数。
  • getContext:在 actions 和 callbacks 中使用,用于访问触发事件的 DOM 元素的本地状态(context)。
  • state:定义代码块的全局响应式数据。
  • actions:包含定义逻辑和更改状态的函数。
  • callbacks:包含响应特定事件或状态更改而自动执行的函数。

内容可能有点多,但别担心!阅读以下章节后,一切都会变得清晰明了。

现在,让我们来了解交互 API 的关键概念:directives、store、state、actions 和 callbacks。

交互API指令

与其他前端库(例如 Alpine.js 和 Vue.js)一样,交互 API 使用特殊的 HTML 属性,使您能够响应页面上的事件、更新应用程序的状态、操作 DOM、应用 CSS 样式、处理用户输入等等。

这些属性被称为 directives,它们允许你将标记代码与底层 JavaScript 逻辑连接起来。

以下列出了你最常用的指令。

功能分类 指令名称 功能描述
激活/命名空间  data-wp-interactive 激活该元素及其子元素的API交互能力,需设置为插件唯一标识符
局部状态  data-wp-context 为当前元素及其子元素提供局部状态(”context”),接受JSON对象(建议通过 PHP 的  wp_interactivity_data_wp_context()render.php 中设置)
属性绑定  data-wp-bind--[attribute] 根据响应式状态或上下文值(布尔/字符串)设置HTML属性(如 disabledvalue
文本操作  data-wp-text 设置元素的innerText内容,仅接受字符串类型数据
CSS类切换  data-wp-class--[classname] 根据布尔值添加/移除CSS类(如:data-wp-class–active=”state.isActive”)
内联样式  data-wp-style--[css-property] 根据布尔值设置/移除内联样式属性(如:data-wp-style–color=”state.textColor”)
事件处理  data-wp-on--[event] 响应标准DOM事件(如 clickmouseover)执行代码
初始化执行  data-wp-init 仅在节点创建时执行一次回调函数
状态监听  data-wp-watch 节点创建时及状态/上下文变化时执行回调函数
列表迭代  data-wp-each 动态渲染元素列表(需配合键值管理使用)

如需查看完整的指令列表,请参阅 Interactivity API 开发说明API 参考文档

全局状态、局部上下文和派生状态

在使用 Interactivity API 之前,您必须熟悉前端开发中状态管理的基本概念。经常使用 React、Vue 或 Angular 进行开发的开发者应该已经熟悉这些概念。对于这些技术的新手,以下是一些通用定义,可能会有所帮助。

全局状态

全局状态(Global state)是指应用程序几乎所有组件都可以访问的一组数据。例如,在 Interactivity API 中,全局状态会影响页面上的所有交互模块,使它们保持同步。例如,当用户将产品添加到购物车时,购物车模块会同步更新。

使用 Interactivity API 时,您应该使用 wp_interactivity_state() 函数在服务器端设置全局状态的初始值。在上述入门项目中,该函数在 render.php 文件中按如下方式使用:

// Adds the global state.
wp_interactivity_state(
'create-block',
array(
'isDark'    => false,
'darkText'  => esc_html__( 'Switch to Light', 'your-interactive-block' ),
'lightText' => esc_html__( 'Switch to Dark', 'your-interactive-block' ),
'themeText'	=> esc_html__( 'Switch to Dark', 'your-interactive-block' ),
)
);

此函数接受两个参数:

  • 存储命名空间的唯一标识符。在本例中,该标识符为 create-block
  • 一个数据数组,如果存在现有存储命名空间,则该数组中的数据将被合并。

然后,使用初始全局状态值来渲染页面。您可以通过在指令属性值中使用 state 直接访问全局状态值,如下面的代码所示:

<button data-wp-on--click="actions.toggleTheme" data-wp-text="state.themeText"></button>

store() 函数提供了从 JavaScript 访问全局状态的主要入口点,但仅限于选定的命名空间。回到初始项目代码,store() 函数在 view.js 文件中的使用方式如下:

import { store, getContext } from '@wordpress/interactivity';
const { state } = store( 'create-block', {
state: { ... },
actions: { ... },
callbacks: { ... },
} );

要访问全局状态,可以使用 state 属性:

actions: {
toggleTheme() {
state.isDark = ! state.isDark;
},
},

本地上下文

本地上下文(Local context)是指只有特定组件及其直接子组件才能访问的数据。WordPress 交互式区块为其自身及其嵌套元素提供独立的状态。

使用交互 API 时,您可以使用 getContext() 函数访问本地上下文。以示例项目为例,当用户点击切换按钮时,会触发 toggleOpen() 操作,从而访问组件的本地上下文:

actions: {
toggleOpen() {
const context = getContext();
context.isOpen = ! context.isOpen;
},
},
  • getContext():获取组件的本地状态对象。该对象的属性在组件标记(render.php)中使用  wp_interactivity_data_wp_context() 函数定义。
  • context.isOpen = ! context.isOpen;:切换组件本地上下文中 isOpen 属性的值。

派生状态

派生状态(Derived state)是指根据现有的全局或本地状态动态计算的数据。

例如,请查看 view.js 文件中的代码,特别是以下部分:

const { state } = store( 'create-block', {
state: {
get themeText() {
return state.isDark ? state.darkText : state.lightText;
},
},
...
}

此代码块定义了在 create-block 命名空间中定义的全局状态下的 themeText 派生状态。

  • get themeText() 不是一个固定值,而是一个每次尝试读取 themeText 属性时都会执行的函数。它不应该像普通函数一样调用,因为交互 API 将其视为状态属性,并在其他状态属性的值发生变化时自动重新计算其值。在上面的代码中,每次 isDark 属性值发生变化时,themeText 属性值都会重新计算。如果 state.isDarktrue,则 themeTextstate.darkText 的值;否则,取 state.lightText 的值。

有关本节所述概念的更全面概述,请参阅“理解全局状态、局部上下文和派生状态”。

动作和回调

动作和回调决定了对用户交互和状态变化的响应。

交互式模块的 actions 部分包含响应用户触发事件而执行的函数。这些函数主要用于修改组件的局部或全局状态。以下代码取自 view.js 文件:

actions: {
toggleOpen() {
const context = getContext();
context.isOpen = ! context.isOpen;
},
...
},
  • 在本代码段中,toggleOpen() 函数使用 getContext()  来访问触发操作以切换 isOpen 属性值的代码块的本地上下文。

类似地,您也可以访问全局状态:

actions: {
...,
toggleTheme() {
state.isDark = ! state.isDark;
},
},
  • toggleTheme() 函数直接访问全局状态对象并更改 isDark 属性的值。

操作通过 data-wp-on--[event] 指令触发。例如,在 render.php 文件中,您会找到以下按钮:

<button
aria-controls="<?php echo esc_attr( $unique_id ); ?>"
>
  • 在这段 HTML 代码中, data-wp-on--click 属性会在用户点击切换按钮时激活 toggleOpen 操作。

callbacks 函数部分包含一些函数,这些函数会在依赖的数据发生变化时自动执行。它们的目的是响应状态变化而产生副作用。

create-block-interactive-template 生成的基础项目中,你会找到以下回调函数:

callbacks: {
logIsOpen: () => {
const { isOpen } = getContext();
// Log the value of `isOpen` each time it changes.
console.log( `Is open: ${ isOpen }` );
},
},
  • logIsOpen  函数使用 isOpen 变量,该变量位于本地上下文中。
  • 回调函数使用 getContext() 获取 isOpen 的值。
  • 每次 isOpen 的值发生变化时,该函数都会向浏览器控制台输出一条消息。

控制台

控制台会显示一条消息,告知用户本地上下文已发生更改。

如何构建交互式模块

现在我们已经掌握了理论知识,是时候开始编写代码了!在本指南的第二部分,您将学习如何创建一个交互式模块,使用户能够将产品添加到理想的购物车中,数量和总计会自动更新。这是一个演示示例,但我们希望它能帮助您清楚地了解如何使用状态、操作和回调。

编辑器中的交互式模块

编辑器中的交互式模块

我们将使用 create-block-interactive-template 创建一个名为“Interactive Counter”的模块。首先,打开命令行工具并输入以下命令:

npx @wordpress/create-block interactive-counter --template @wordpress/create-block-interactive-template

接下来,导航到你的新项目目录并运行第一次构建。

cd interactive-counter && npm run build

现在用代码编辑器打开项目。在 /src 目录下,找到 block.json 文件。它应该类似于这样:

{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "create-block/interactive-counter",
"version": "0.1.0",
"title": "Interactive Counter",
"category": "widgets",
"icon": "media-interactive",
"description": "An interactive block with the Interactivity API.",
"supports": {
"interactivity": true
},
"textdomain": "interactive-counter",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"render": "file:./render.php",
"viewScriptModule": "file:./view.js"
}

您可以随意自定义,但请确保不要修改上述基本字段。

edit.js文件

下一步是创建将在编辑器中显示的区块。为此,您需要编辑 /src/edit.js 文件。打开该文件并按如下方式修改:

import { __ } from '@wordpress/i18n';
import { useBlockProps } from '@wordpress/block-editor';
import './editor.scss';
export default function Edit({ attributes, setAttributes }) {
const blockProps = useBlockProps();
const products = [
{ id: 'product1', name: __('Product 1', 'interactive-counter'), price: 10.00 },
{ id: 'product2', name: __('Product 2', 'interactive-counter'), price: 15.00 },
{ id: 'product3', name: __('Product 3', 'interactive-counter'), price: 20.00 },
];
return (
<div {...blockProps}>
<h3>{__('Shopping Cart', 'interactive-counter')}</h3>
<ul>
{products.map((product) => (
<li key={product.id} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '10px' }}>
<span style={{ flex: 1 }}>{product.name} - ${product.price.toFixed(2)}</span>
<div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}>
<button disabled>-</button>
<span>0</span>
<button disabled>+</button>
</div>
<span style={{ flex: 1, textAlign: 'right' }}>
{__('Subtotal:', 'interactive-counter')} $0.00
</span>
</li>
))}
</ul>
<div style={{ borderTop: '1px solid #ccc', paddingTop: '15px' }}>
<p style={{ display: 'flex', justifyContent: 'space-between' }}>
<strong>{__('Subtotal:', 'interactive-counter')}</strong>
<span>$0.00</span>
</p>
<p style={{ display: 'flex', justifyContent: 'space-between' }}>
<strong>{__('Tax (22%):', 'interactive-counter')}</strong>
<span>$0.00</span>
</p>
<p style={{ display: 'flex', justifyContent: 'space-between' }}>
<strong>{__('Total:', 'interactive-counter')}</strong>
<span>$0.00</span>
</p>
</div>
<p>{__('Quantities and totals will be interactive in the frontend.', 'interactive-counter')}</p>
</div>
);
}

这段代码会在后端生成一个自定义区块。该区块仅在前端可交互。有关 /src/edit.js 文件的更多详细信息,请参阅我们的 Gutenberg 区块开发指南

render.php文件

接下来要编辑的文件是 /src/render.php。打开该文件,并将现有代码替换为以下代码:

<?php
/**
* Render callback for the interactive-counter block.
*/
$products = [
['id' => 'product1', 'name' => __('Product 1', 'interactive-counter'), 'price' => 10.00],
['id' => 'product2', 'name' => __('Product 2', 'interactive-counter'), 'price' => 15.00],
['id' => 'product3', 'name' => __('Product 3', 'interactive-counter'), 'price' => 20.00],
];
// Initialize global state
wp_interactivity_state('interactive-counter', [
'products' => array_map(function ($product) {
return [
'id' => $product['id'],
'name' => $product['name'],
'price' => $product['price'],
'quantity' => 0,
'subtotal' => '0.00',
];
}, $products),
'vatRate' => 0.22,
]);

这段代码的作用如下:

  • 首先,它创建一个硬编码的产品数组。每个产品都有一个 ID、一个名称和一个价格。
  • 接下来,它使用 wp_interactivity_state 初始化全局状态。第一个参数是商店名称,必须与 view.js 中使用的名称一致。
  • 然后,它将之前的产品数组映射到一个新的 products  数组,并在原始数组的属性中添加数量和小计。这个新数组提供了您将在 view.js 中使用的数据结构。
  • vatRate 设置税额计算的默认值。

接下来,将以下内容添加到上面的代码中:

<div <?php echo get_block_wrapper_attributes(); ?>>
<h3><?php echo esc_html__('Cart', 'interactive-counter'); ?></h3>
<ul>
<?php foreach ($products as $index => $product) : ?>
<li data-wp-context='{
"productId": "<?php echo esc_attr($product['id']); ?>",
"quantity": 0,
"subtotal": "0.00"
}' 
data-wp-bind--data-wp-context.quantity="state.products[<?php echo $index; ?>].quantity" 
data-wp-bind--data-wp-context.subtotal="state.products[<?php echo $index; ?>].subtotal">
<span class="product-name"><?php echo esc_html($product['name']); ?> - $<?php echo esc_html(number_format($product['price'], 2)); ?></span>
<div class="quantity-controls">
<button>-</button>
<span>0</span>
<button>+</button>
</div>
<span class="product-subtotal">
<?php echo esc_html__('Subtotal:', 'interactive-counter'); ?>
$<span>0.00</span>
</span>
</li>
<?php endforeach; ?>
</ul>
<div class="totals">
<p>
<strong><?php echo esc_html__('Subtotal:', 'interactive-counter'); ?></strong>
$ <span>0.00</span>
</p>
<p>
<strong><?php echo esc_html__('Tax (22%):', 'interactive-counter'); ?></strong>
$ <span>0.00</span>
</p>
<p>
<strong><?php echo esc_html__('Total:', 'interactive-counter'); ?></strong>
$ <span>0.00</span>
</p>
</div>
</div>

这段代码的作用如下:

  • div 容器中的 get_block_wrapper_attributes()  函数是一个 WordPress 函数,用于生成区块的标准属性。在本例中,它生成了类属性 wp-block-create-block-interactive-counter
  • data-wp-interactive 属性使该区块具有交互性。
  • data-wp-init 属性触发了 view.js 中定义的初始化回调。
  • foreach 循环为 products 数组中的每个产品生成一个列表项。
  • data-wp-context 定义了区块的本地上下文。
  • data-wp-binddata-wp-context.quantity 的值绑定到全局属性 state.products[$index].quantity
  • 下一行代码也做了同样的处理,用于计算小计。
  • 以下两个按钮通过 data-wp-on--click 属性激活递减和递增操作。
  • span 元素中的 data-wp-text 属性会根据 context.quantity 的当前值更新元素的内容。

其余代码无需赘述,我们继续查看下一个文件。

view.js文件

此文件包含交互式模块的逻辑。

import { store, getContext } from '@wordpress/interactivity';
store('interactive-counter', {
state: {
get subtotal() {
const { products } = store('interactive-counter').state;
return products
.reduce((sum, product) => sum + product.price * (product.quantity || 0), 0)
.toFixed(2);
},
get vat() {
const { subtotal, vatRate } = store('interactive-counter').state;
return (subtotal * vatRate).toFixed(2);
},
get total() {
const { subtotal, vat } = store('interactive-counter').state;
return (parseFloat(subtotal) + parseFloat(vat)).toFixed(2);
},
},
actions: {
increment: () => {
const context = getContext();
const { products } = store('interactive-counter').state;
const product = products.find(p => p.id === context.productId);
if (product) {
product.quantity = (product.quantity || 0) + 1;
product.subtotal = (product.price * product.quantity).toFixed(2);
context.quantity = product.quantity;
context.subtotal = product.subtotal;
console.log(`Incremented ${context.productId}:`, { quantity: product.quantity, subtotal: product.subtotal, context });
} else {
console.warn('Product not found:', context.productId);
}
},
decrement: () => {
const context = getContext();
const { products } = store('interactive-counter').state;
const product = products.find(p => p.id === context.productId);
if (product && (product.quantity || 0) > 0) {
product.quantity -= 1;
product.subtotal = (product.price * product.quantity).toFixed(2);
context.quantity = product.quantity;
context.subtotal = product.subtotal;
console.log(`Decremented ${context.productId}:`, { quantity: product.quantity, subtotal: product.subtotal, context });
} else {
console.warn('Cannot decrement:', context.productId, product?.quantity);
}
},
},
callbacks: {
init: () => {
const { products } = store('interactive-counter').state;
products.forEach((product, index) => {
product.quantity = 0;
product.subtotal = '0.00';
console.log(`Initialized product ${index}:`, { id: product.id, quantity: product.quantity, subtotal: product.subtotal });
});
},
},
});

此文件定义了 interactive-counter 命名空间的存储。它管理状态、操作和回调:

store('interactive-counter', {
state: { ... },
actions: { ... },
callbacks: { ... },
});

让我们仔细看看。

  • state:定义了三个计算状态属性(getter): subtotalvattotal。这些函数从全局状态中检索值并计算要返回的值。
  • actions:定义了两个在事件发生时执行的函数:incrementDecrement。这些函数从全局状态中检索 products 数组,根据 context.productId 从本地上下文中检索当前产品,更新当前产品的属性值(quantitysubtotal),并将本地上下文与新值同步。
  • callbacks:定义了一个用于初始化的 init 回调函数。

下图显示了前端的交互式模块。

交互式计数器

使用交互式 API 构建的交互式计数器

小结

在本文中,我们介绍了 WordPress 交互式 API 的主要特性。我们深入探讨了全局状态、局部上下文、指令、操作和回调等关键概念。您学习了如何使用  @wordpress/create-block-interactive-template 从头开始​​创建一个交互式区块,并通过创建一个与用户输入交互的真实区块来实践所学。

我们希望本文能为您提供必要的工具和知识,帮助您使用 WordPress 交互式 API 创建出色、动态且交互式的 WordPress 网站。

Happy coding!

评论留言

闪电侠

(工作日 10:00 - 18:30 为您服务)

2025-12-14 12:36:31

您好,无论是售前、售后、意见建议……均可通过联系工单与我们取得联系。

您也可选择聊天工具与我们即时沟通或点击查看:

您的工单我们已经收到,我们将会尽快跟您联系!
取消
选择聊天工具: