Chris 最近发布了一个简洁的 WordPress 古腾堡编辑器的 CodePen 嵌入块。它允许您只需输入 Pen 的 URL 即可嵌入它。从那里,您可以控制大小、主题以及初始加载时呈现的默认选项卡。非常棒!

但这让我思考:使用 Sanity Studio 的可移植文本编辑器 重现它有多难?(剧透:没那么难)。由于我已经知道如何操作,我从头到尾只花了不到七分钟。本教程将引导您了解如何使用 studio,以及如何为 CodePen 嵌入添加架构和自定义预览组件。
所以这是我重现 @chriscoyier 的 CodePen 古腾堡块,用于 @sanity_io 的富文本编辑器,时间不到 7 分钟(3 倍速视频)。最棒的是,您实际上只需要存储结构化数据,使其可查询、面向未来,并且易于与您喜欢的任何前端集成。 https://#/psPn6NtPjz pic.twitter.com/6aSGKerHfO
— knut(在旧金山 🇺🇸)(@kmelve) 2020年1月18日
感觉太酷了,我也想教大家怎么做。让我们深入了解一下。
在本地启动并运行 Sanity Studio
首先,您需要在您的机器上本地安装 Sanity Studio。在本教程中,我们将使用您可以从命令行启动的博客 studio,但您也可以查看 sanity.io/create 上的不同启动器。您也应该能够使用其中一个。
本教程假设您对 JavaScript 有所了解。它将使用一些 React,但只有一小部分。如果您还没有安装,则应该 安装 node 和 npm。
哦,您还需要 Sanity CLI,您可以使用命令行获取它
npm install --global @sanity/cli
安装完成后,您可以通过运行命令 sanity init
来使用新项目启动一个新的 Sanity Studio。它将允许您使用您的 Google 或 GitHub 帐户登录(或使用电子邮件/密码创建新帐户)。为您的项目命名并按照说明操作。当提供项目模板选项时,选择博客选项。
? Select project template
Movie project (schema + sample data)
E-commerce (schema + sample data)
❯ Blog (schema)
Clean project with no predefined schemas
完成这些步骤后,更改目录(cd
)到新项目文件夹,并在您喜欢的代码编辑器中打开它。要启动开发服务器,该服务器还将在您进行更改时热重载您的 studio,请运行 sanity start
。要停止此服务器,您可以在大多数命令行工具中按 ctrl + C
。
添加 CodePen 嵌入的架构
架构定义了 Studio 中可用的文档类型以及它们具有的输入字段。这些架构是在 JavaScript 对象中定义的,您将它们导入到 schemas.js
文件中,在其中将其导出为一个函数,Studio 将该函数转换为其 UI。您可以使用这些架构做很多事情,但在本教程中,我们将保持其简单性。
首先在 /yourproject/schemas
中添加一个名为 codepen.js
的新文件。然后键入以下代码
export default {
name: "codepen",
type: "object",
title: "CodePen Embed",
fields: [
{
name: "url",
type: "url",
title: "CodePen URL"
}
]
};
然后您可以转到 /yourproject/schemas/schema.js
并向其中添加以下两行代码
import createSchema from "part:@sanity/base/schema-creator";
import schemaTypes from "all:part:@sanity/base/schema-type";
import blockContent from "./blockContent";
import category from "./category";
import post from "./post";
import author from "./author";
import codepen from "/codepen.js"; // <= first import the object
export default createSchema({
name: "default",
types: schemaTypes.concat([
post,
author,
category,
blockContent,
codepen // <= add it to the schema types array
])
});
我们刚才做了什么?好吧,我们现在已将此 CodePen 对象作为 Studio 中其他架构的 type
提供。换句话说,您现在可以添加 type: 'codepen'
以在添加字段的架构代码中的任何其他位置获取这些字段。将此类型添加到富文本字段也是我们的下一步。坚持住!
将 CodePen 字段添加到富文本编辑器
在深入研究代码之前,让我们退一步,看看我们操作的数据格式以及 WordPress 和 Sanity 如何略有不同。
虽然 Gutenberg 在其运行时将富文本存储为 JSON(这很棒!),但开发人员最终处理的主要是此内容作为 HTML 和 HTML 注释内的 JSON 对象。
Sanity 将富文本内容存储和分发为 可移植文本,然后开发人员在其前端进行序列化。这意味着您可以对富文本内容的呈现方式进行细粒度控制,让您可以为喜爱的框架使用自定义组件,无论是 React、Vue、Svelte 还是 .NET、PHP,甚至 Markdown。
换句话说,您将内容作为 Sanity 后端的 结构化数据 存储,然后决定如何在前端组件中使用这些数据。但闲话少说,让我们回到代码吧!
打开 /schemas/blockContent.js
并注意它属于 array
类型。是的,富文本是不同类型的数组,其中一个必须是 block
类型(文本段落存储在其中)。因此,创建富文本的最简单方法是以下架构定义
export default {
name: "body",
type: "array",
title: "Body",
of: [
{
type: "block"
}
]
};
现在,blockContent.js
还有很多其他内容。您可以看到 styles
、lists
、marks
等。所有这些都定义了作者应该可以使用哪些属性。在顶层数组中,有两种类型 block
和 image
。我们将添加第三个,codepen
export default {
title: "Block Content",
name: "blockContent",
type: "array",
of: [
{
type: "block"
// ...
},
{
type: "image",
options: { hotspot: true }
},
{
type: "codepen"
}
]
};
保存文件,就是这样!如果您现在在命令行中运行 sanity start
(假设您还没有运行),并在 https://localhost:3333
上打开 Studio,您应该能够在“post”类型的富文本编辑器中找到您的新字段。

如果您尝试使用新按钮,您将获得一个带有您在上一节中定义的 URL 字段的模态框。随意添加您找到的酷炫 CodePen 的 URL。我们将使用来自传奇人物 Sara Drasner 的这个,它很酷。
不过,仅在编辑器中显示 URL 值并不特别鼓舞人心。因此,让我们继续添加实际的 CodePen 嵌入,以便我们可以在编辑器中直接与之交互!
添加 CodePen 嵌入作为预览
再次打开 /yourproject/schemas/codepen.js
。现在我们将为我们的预览创建一个小的 React 组件。首先在顶部导入 React,以及我们将转换为嵌入的 React 组件的样板代码
import React from "react";
const CodePenPreview = ({ value }) => {
return <pre>{JSON.stringify(value, null, 2)}</pre>;
};
export default {
name: "codepen",
type: "object",
title: "CodePen Embed",
fields: [
{
name: "url",
type: "url",
title: "CodePen URL"
}
]
};
JSON.stringify
部分是一种临时的小方法,用于以可读的方式输出传入的数据。您也可以使用 console.log(value)
,但谁有时间打开开发者控制台呢?
现在您必须告诉 Sanity 如何在预览中使用此组件。以及它应该为预览组件中的 value
选择对象中的哪些字段。
import React from "react";
const CodePenPreview = ({ value }) => {
return <pre>{JSON.stringify(value, null, 2)}</pre>;
};
export default {
name: "codepen",
type: "object",
title: "CodePen Embed",
preview: {
select: {
url: "url"
},
component: CodePenPreview
},
fields: [
{
name: "url",
type: "url",
title: "CodePen URL"
}
]
};
保存更改后,编辑器应该如下所示

酷!现在我们要获取 url
值,并以某种方式将其与 CodePen 嵌入集成。最简单的方法是拟合 CodePen 的 iFrame 嵌入的标记,并将其拟合到我们 React 中的预览组件中。
原始的 iFrame 元素将如下所示
<iframe height="265" style="width: 100%;" scrolling="no" title="React Animated Page Transitions" src="https://codepen.io/sdras/embed/gWWQgb?height=265&theme-id=dark&default-tab=js,result" frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen <a href='https://codepen.io/sdras/pen/gWWQgb'>React Animated Page Transitions</a> by Sarah Drasner
(<a href='https://codepen.io/sdras'>@sdras</a>) on <a href='https://codepen.io'>CodePen</a>.
</iframe>
如果我们将此代码段粘贴到我们的预览组件中,它将几乎可以工作。为了使其 与 JSX 兼容,您需要对一些 HTML 属性进行一些更改。请确保您更改
style="width: 100%;"
为style={{width: "100%"}}
frameborder="no"
为frameBorder="no"
allow-transparency="true"
为allowTransparency
allow-fullscreen="true"
为allowFullScreen
您可以删除 iframe 内部的内容(链接等),因为在 studio 内它不是特别有用。我们最终应该得到如下内容
import React from "react";
import Codepen from "react-codepen-embed";
const CodePenPreview = ({ value }) => {
return (
<iframe
height="265"
style={{ width: '100%' }}
scrolling="no"
title="React Animated Page Transitions"
src="https://codepen.io/sdras/embed/gWWQgb?height=370&theme-id=dark&default-tab=js,result"
frameBorder="no"
allowTransparency
allowFullScreen
/>);
};
// ...
保存后,我们应该能够在富文本编辑器中看到 CodePen 嵌入

请注意,iFrame 具有一个嵌入 URL,其中包含一些关于如何显示它的参数。当然,我们可以要求某人深入 CodePen 获取此 URL,但最好使用常规 URL。我们将努力将其重新组装成我们需要的东西
最后一部分是从字段中获取 URL,并从中提取 hash
和 user
。
我们将 URL 字符串以正斜杠为分隔符分割成数组。然后我们使用数组解构将不同的数组元素分配给变量。由于我们只需要 user
和 hash
,因此我们将其他位置留空。这种方法并非万无一失,因为它假设了 URL 的特定格式,但对于此示例来说它可以正常工作。然后我们使用 模板字面量 重新组装 embedUrl
。
import React from "react";
const CodePenPreview = ({ value }) => {
const { url } = value;
if (!url) {
return (<div>Add a CodePen URL</div>)
}
const splitURL = url.split("/");
// [ 'https:', '', 'codepen.io', 'sdras', 'pen', 'gWWQgb' ]
const [, , , user, , hash] = splitURL;
const embedUrl = `https://codepen.io/${user}/embed/${hash}?height=370&theme-id=dark&default-tab=result`;
return (
<iframe
height="370"
style={{ width: '100%' }}
scrolling="no"
title="CodePen Embed"
src={embedUrl}
frameBorder="no"
allowTransparency
allowFullScreen
/>
);
};
// ...
保存更改,瞧!我们几乎完成了自定义 CodePen 块!
更进一步
现在,您可能已经注意到 Chris 在他的自定义块中添加了更多设置。没有什么能阻止我们也这样做!如果我们查看我们安装的 React CodePen 嵌入组件 的文档,我们会找到一个它可以接受的属性表。我们可以将这些属性作为字段添加到模式定义中。例如,如果我们想添加 themeId
,我们可以按如下方式进行
import React from "react";
import Codepen from "react-codepen-embed";
const CodePenPreview = ({ value }) => {
const { url, themeId = "dark" } = value; // <= add themeId here, default it to "dark"
if (!url) {
return (<div>Add a CodePen URL</div>)
}
const splitURL = url.split("/");
// [ 'https:', '', 'codepen.io', 'sdras', 'pen', 'gWWQgb' ]
const [, , , user, , hash] = splitURL;
const embedUrl = `https://codepen.io/${user}/embed/${hash}?height=370&theme-id=${themeId}&default-tab=result`; // <= add themeId here
return (
<iframe
height="370"
style={{ width: '100%' }}
scrolling="no"
title="CodePen Embed"
src={embedUrl}
frameBorder="no"
allowTransparency
allowFullScreen
/>
);
};
export default {
name: "codepen",
type: "object",
title: "CodePen Embed",
preview: {
select: {
url: "url",
themeId: "themeId" // <= add themeId here
},
component: CodePenPreview
},
fields: [
{
name: "url",
type: "url",
title: "CodePen URL"
},
// Add the new field below
{
name: "themeId",
type: "string",
title: "Theme ID",
description: 'You can use "light" and "dark" also.'
}
]
};
结论
我们刚刚了解了 Sanity Studio 的模式是如何工作的,并学习了如何为自定义组件创建预览!希望您现在已经了解了如何使用这些相同的原理创建几乎任何具有预览功能的自定义组件。如果您做到了,我非常想知道,您可以在 Twitter 上或在评论中告诉我。
酷!您知道如何在块中支持表格吗?