WordPress源码深度解析之:`Block`的`variations`:如何创建块的变体以提供不同的预设样式。

早上好,各位码农和准码农们!今天咱们来聊聊WordPress Gutenberg编辑器里一个相当给力,但又常常被忽略的功能:Blockvariations。简单来说,它能让你像给乐高积木换皮肤一样,给你的自定义块提供不同的预设样式,省时省力,还让用户体验蹭蹭往上涨。准备好了吗?咱们这就开始深入探讨!

一、什么是Block Variations?

想象一下,你辛辛苦苦开发了一个“超级按钮”块。这个按钮可以有不同的颜色、尺寸、形状,甚至不同的点击事件。如果没有variations,你可能需要做一大堆的设置选项,让用户自己去调整,这简直是噩梦!

Block variations就像是预设方案,你可以预先定义好几种不同样式的“超级按钮”,用户只需要轻轻一点,就能切换到自己想要的风格。

举个例子,你可以创建一个“红色大按钮”、“蓝色小按钮”、“幽灵按钮”等变体,用户无需手动调整颜色、大小,直接选择即可。

二、Block Variations的优势

  • 提升用户体验: 预设样式,一键切换,降低学习成本。
  • 代码复用: 避免重复编写样式代码,提高开发效率。
  • 一致性: 确保网站风格统一,提升专业度。
  • 可维护性: 修改变体样式,所有使用该变体的块都会自动更新。

三、如何使用Block Variations?

要使用Block Variations,你需要修改你的块的 block.json 文件,并使用 JavaScript 代码注册和管理这些变体。

1. 修改 block.json 文件

在你的块的 block.json 文件中,添加 variations 属性。variations 属性是一个数组,每个元素代表一个变体。

{
  "name": "my-custom-block/super-button",
  "title": "超级按钮",
  "description": "一个可以自定义样式的按钮。",
  "category": "common",
  "icon": "button",
  "keywords": [ "button", "link" ],
  "attributes": {
    "buttonText": {
      "type": "string",
      "default": "点击这里"
    },
    "buttonColor": {
      "type": "string",
      "default": "primary"
    }
  },
  "supports": {
    "align": true
  },
  "variations": [
    {
      "name": "primary-button",
      "title": "主按钮",
      "description": "醒目的主按钮。",
      "isDefault": true, // 设置默认变体
      "attributes": {
        "buttonColor": "primary"
      },
      "icon": "admin-site-alt" // 变体的图标
    },
    {
      "name": "secondary-button",
      "title": "次按钮",
      "description": "不那么醒目的次按钮。",
      "attributes": {
        "buttonColor": "secondary"
      },
      "icon": "admin-site"
    },
    {
      "name": "ghost-button",
      "title": "幽灵按钮",
      "description": "透明背景的幽灵按钮。",
      "attributes": {
        "buttonColor": "ghost"
      },
      "icon": "admin-appearance"
    }
  ],
  "textdomain": "my-custom-block",
  "editorScript": "file:./index.js",
  "style": "file:./style-index.css"
}

让我们逐个解释一下这些属性:

  • name (必需): 变体的唯一标识符。通常使用 block-name/variation-name 的格式。
  • title (必需): 变体的显示名称,用户在编辑器中看到的。
  • description: 变体的描述,帮助用户了解它的用途。
  • isDefault: 布尔值,表示是否为默认变体。如果为 true,则在插入块时,默认使用此变体。
  • attributes: 一个对象,包含该变体需要覆盖的属性值。在本例中,我们通过设置 buttonColor 属性来改变按钮的颜色。
  • icon: 变体的图标,可以是 dashicon 的名称(如 'admin-site'),也可以是 SVG 字符串。

2. JavaScript 代码 (index.js)

虽然 block.json 定义了变体的基本信息,但你可能需要在 JavaScript 代码中做一些额外的处理,比如根据 buttonColor 属性来应用不同的 CSS 类。

import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps, RichText } from '@wordpress/block-editor';
import './style.scss';

registerBlockType('my-custom-block/super-button', {
  /**
   * @see ./block.json
   */
  edit: (props) => {
    const { attributes, setAttributes } = props;
    const { buttonText, buttonColor } = attributes;

    const onChangeButtonText = (newText) => {
      setAttributes({ buttonText: newText });
    };

    return (
      <div {...useBlockProps()}>
        <RichText
          tagName="a" // 渲染为链接
          className={`super-button super-button--${buttonColor}`} // 动态添加 CSS 类
          value={buttonText}
          onChange={onChangeButtonText}
          placeholder="按钮文字"
        />
      </div>
    );
  },

  save: (props) => {
    const { attributes } = props;
    const { buttonText, buttonColor } = attributes;

    return (
      <div {...useBlockProps.save()}>
        <a className={`super-button super-button--${buttonColor}`}>
          {buttonText}
        </a>
      </div>
    );
  },
});

这段代码做了以下事情:

  • registerBlockType: 注册你的块。
  • edit: 定义块在编辑器中的显示和交互。
  • save: 定义块在前端的显示。
  • useBlockProps: 一个 React Hook,用于获取标准的块属性,例如 className
  • RichText: 一个组件,用于创建可编辑的文本区域。
  • className={super-button super-button–${buttonColor}`}: 根据buttonColor` 属性动态添加 CSS 类。

3. CSS 样式 (style.scss)

最后,你需要定义你的 CSS 样式,根据不同的 buttonColor 来应用不同的样式。

.super-button {
  display: inline-block;
  padding: 10px 20px;
  border-radius: 5px;
  text-decoration: none;
  color: #fff;
  font-weight: bold;

  &--primary {
    background-color: #007bff;
  }

  &--secondary {
    background-color: #6c757d;
  }

  &--ghost {
    background-color: transparent;
    border: 2px solid #fff;
    color: #fff;
  }
}

这段 CSS 代码定义了 super-button 的基本样式,并根据不同的 buttonColor (primary, secondary, ghost) 来应用不同的背景颜色和边框。

四、代码示例:一个更复杂的例子 – 图像块变体

让我们来看一个更复杂的例子:一个图像块,它可以有不同的对齐方式和圆角。

block.json:

{
  "name": "my-custom-block/image-with-variations",
  "title": "带变体的图像",
  "description": "一个可以自定义对齐方式和圆角的图像块。",
  "category": "common",
  "icon": "format-image",
  "attributes": {
    "imageUrl": {
      "type": "string",
      "default": ""
    },
    "alignment": {
      "type": "string",
      "default": "none"
    },
    "roundedCorners": {
      "type": "boolean",
      "default": false
    }
  },
  "supports": {
    "align": [ "left", "center", "right" ]
  },
  "variations": [
    {
      "name": "left-aligned",
      "title": "左对齐",
      "description": "将图像左对齐。",
      "attributes": {
        "alignment": "left"
      },
      "icon": "align-left"
    },
    {
      "name": "center-aligned",
      "title": "居中对齐",
      "description": "将图像居中对齐。",
      "attributes": {
        "alignment": "center"
      },
      "isDefault": true,
      "icon": "align-center"
    },
    {
      "name": "right-aligned",
      "title": "右对齐",
      "description": "将图像右对齐。",
      "attributes": {
        "alignment": "right"
      },
      "icon": "align-right"
    },
    {
      "name": "rounded",
      "title": "圆角",
      "description": "为图像添加圆角。",
      "attributes": {
        "roundedCorners": true
      },
      "icon": "image-filter",
      "isActive": [ "attributes.roundedCorners" ] // 条件激活,稍后解释
    }
  ],
  "textdomain": "my-custom-block",
  "editorScript": "file:./index.js",
  "style": "file:./style-index.css"
}

index.js:

import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps, MediaPlaceholder } from '@wordpress/block-editor';
import './style.scss';

registerBlockType('my-custom-block/image-with-variations', {
  /**
   * @see ./block.json
   */
  edit: (props) => {
    const { attributes, setAttributes } = props;
    const { imageUrl, alignment, roundedCorners } = attributes;

    const onSelectImage = (media) => {
      setAttributes({ imageUrl: media.url });
    };

    return (
      <div {...useBlockProps()}>
        {imageUrl ? (
          <img
            src={imageUrl}
            alt="Custom Image"
            style={{
              float: alignment === 'none' ? undefined : alignment,
              borderRadius: roundedCorners ? '10px' : '0',
            }}
          />
        ) : (
          <MediaPlaceholder
            onSelect={onSelectImage}
            accept="image/*"
            multiple={false}
            labels={{
              title: '选择图像',
              instructions: '上传或选择一个图像',
            }}
          />
        )}
      </div>
    );
  },

  save: (props) => {
    const { attributes } = props;
    const { imageUrl, alignment, roundedCorners } = attributes;

    return (
      <div {...useBlockProps.save()}>
        {imageUrl && (
          <img
            src={imageUrl}
            alt="Custom Image"
            style={{
              float: alignment === 'none' ? undefined : alignment,
              borderRadius: roundedCorners ? '10px' : '0',
            }}
          />
        )}
      </div>
    );
  },
});

style.scss:

// 这里可以添加一些全局样式,例如图像的最大宽度

在这个例子中,我们创建了三个对齐方式的变体和一个圆角变体。注意,圆角变体使用了 isActive 属性。

五、isActive 属性:动态激活变体

isActive 属性允许你根据块的当前属性动态地激活变体。它接受一个属性名称的数组,当这些属性的值与变体中定义的属性值匹配时,该变体将被激活。

在上面的例子中,rounded 变体的 isActive 属性是 [ "attributes.roundedCorners" ]。这意味着只有当块的 roundedCorners 属性为 true 时,该变体才会被激活。

六、代码之外的思考:变体的最佳实践

  • 不要滥用变体: 只有当变体之间有显著差异时才使用。如果只是细微的样式调整,使用块的属性更合适。
  • 保持变体简洁: 避免创建过于复杂的变体。每个变体应该只关注一个特定的方面,例如颜色、对齐方式或形状。
  • 提供清晰的描述: 为每个变体提供清晰的描述,帮助用户了解它的用途。
  • 考虑性能: 过多的变体可能会影响编辑器的性能。只创建必要的变体,并优化你的代码。

七、常见问题解答

  • 问:我可以在变体中使用自定义字段吗?

    • 答:当然可以。你可以在变体的 attributes 属性中定义自定义字段,并在 JavaScript 代码中访问它们。
  • 问:我可以在变体中使用复杂的逻辑吗?

    • 答:尽量避免在变体中使用复杂的逻辑。如果需要复杂的逻辑,最好在 JavaScript 代码中实现。
  • 问:如何调试变体?

    • 答:可以使用浏览器的开发者工具来检查块的属性和样式。也可以使用 console.log 来输出调试信息。

八、总结

Block variations 是一个强大的工具,可以让你轻松地创建具有不同预设样式的块。通过合理地使用变体,你可以提高用户体验,减少代码重复,并确保网站风格的统一。

希望今天的讲座对你有所帮助!下次再见,各位码农! 祝大家 Bug 越来越少,头发越来越多!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注