搜索
首页web前端css教程构建互动无花果小部件

Building Interactive Figma Widgets

Figma一直鼓励开发者和设计师之间的协作,并凭借其丰富的社区插件库而蓬勃发展。需要3D元素?有插件!需要抽象的SVG?也有插件!

然而,Figma的设计部分一直相对静态——始终使用不可移动的矩形,通过预定义的用户交互连接在一起。但如果我说你的设计可以突然栩栩如生——可以动画化、交互式,甚至是有状态的,你会怎么想?那么,概念与实现之间还有什么区别呢?

Figma在6月份宣布将推出基于JavaScript的小部件。现在,设计师可以直接在Figma中浏览和实现逻辑驱动的组件!

让我们一起了解一下Widgets API!想知道它是什么以及如何使用它吗?这正是我们将在本文中一起探讨的内容。

Figma小部件开启无限可能

想象一下,你和你的合作伙伴日夜合作设计一个大型餐厅应用程序。你们都在同一个Figma画板上协作;你们共享完全相同的文档,更改实时发生。

当然,你已经知道协作不仅仅包括设计过程:

  • 项目管理,
  • 举办投票,
  • 导入和可视化模拟数据,
  • 也许甚至玩一个多人游戏来放松一下长时间的工作。

只需要一个人管理所有内容并向小组的其他成员发送链接。但是,这效率不高,对吧?

这就是小部件发挥作用的地方。我们可以想象做到所有这些——是的,所有这些——无需离开Figma。

以下是一些你可能希望在Figma中使用小部件的方式:

  • 为Jira和Asana创建任务
  • 在GitHub中创建问题
  • 显示动态数据
  • 录制语音备忘录
  • 创建任务列表
  • 浪费时间玩井字游戏
  • 追踪活动
  • 创建计时器

等等等等。正如你所看到的,已经有大量的小部件可以自由地用于你的文档中。事实上,你可以直接从“小部件”菜单(Shift I)将小部件添加到你的画板中。

但我们不是来学习如何使用小部件的,因为这很容易。让我们做我们最擅长的事情:我们将创建我们自己的Figma小部件!这个小部件将以Chris Coyier的设计报价网站为灵感。我们将获取API,将其馈送到小部件,然后直接在Figma中显示随机的设计报价。

我们需要什么

我不喜欢当坏消息的传播者,但是为了开发小部件,你必须在Windows或Mac上。Linux用户,对不起,你运气不好。(如果你想继续学习,你仍然可以使用虚拟机。)

我们将下载Figma桌面应用程序。最简单的入门方法是从应用程序中直接生成小部件模板。

让我们通过打开小部件菜单(Shift I)、切换到开发选项卡并创建一个新项目来创建一个新的画板。

之后,Figma会提示你命名新的小部件,并决定它是否更适合设计画板或FigJam画板。对于本文的目的,前一个选项就足够了。

定制并没有就此结束;Figma还会让你选择从预制计数器小部件或启用iFrame的替代方案开始,该方案还允许你访问Canvas和Fetch API(以及所有其他浏览器API)。我们将选择简单的“空”选项,但我们最终会自己修改它以使用Fetch API。

然后,系统会提示你将新的Widget项目保存到系统中的特殊目录。完成后,启动你的终端并将其定向到该文件夹。现在还不要运行任何命令——我们稍后会这样做,并故意出现错误,目的是学习更多关于Widgets API的知识。

设计小部件

我们直接从Chris Coyier的设计报价网站获取设计。所以,让我们去那里,通过启动DevTools来深入研究。

我在这里使用的两个关键快捷键是Ctrl Shift C(或Cmd Shift C)来切换“拾取元素”工具,以及Shift 单击来将颜色格式更改为HEX代码。我们这样做是为了了解Chris网站中使用的颜色、字体、字体粗细和字体大小。所有这些信息对于在Figma中构建一个非常相似的Widget至关重要,这将是我们的下一步!你可以抓取设计好的组件并将其用于你自己的画布。

我在这里不会详细介绍,因为本文的主题是通过编写代码来构建小部件。但我必须强调,精心设计小部件的样式非常重要……CSS-Tricks已经有大量面向设计的Figma教程;你不会后悔将它们添加到你的阅读列表中。

为我们的Widget创建布局

设计完成后,是时候拿出我们的编程手指,开始构建我们小部件的齿轮了。

Figma如何将其设计构建块转换为类似React的组件非常有趣。例如,具有自动布局功能的框架元素在代码中表示为<autolayout></autolayout>组件。除此之外,我们还将使用另外两个组件:<text></text><svg></svg>

看看我的Figma画板……我正是要求你关注对象树。这是我们需要能够将我们的Widget设计转换为JSX代码的关键。

如你所见,我们的设计报价小部件需要导入三个组件。考虑到完整的API只包含八个基于图层的节点,这是一个相当数量的组件。但正如你很快就会看到的,这些模块足以制作各种布局。

<code>// code.tsx
const { widget } = figma;
const { AutoLayout, Text, SVG } = widget;</code>

有了这个,我们就可以像在React中一样构建我们小部件的骨架了:

<code>function QuotesWidget() {
  const quote = `...`;
  const author = `...`;

  return (
    <autolayout><svg></svg><autolayout><text>{quote}</text><text>— {author}</text></autolayout><svg></svg></autolayout>
  );
}

widget.register(QuotesWidget);</code>

这段代码至少可以说是非常混乱的。现在,我们无法区分设计图层。幸运的是,我们可以通过使用name属性轻松解决这个问题。

<code><autolayout name="{" quote><svg name="{" leftquotationmark></svg><autolayout name="{" quotecontent><text name="{" quotetext>{quote}</text><text name="{" quoteauthor>— {author}</text></autolayout><svg name="{" rightquotationmark></svg></autolayout>;</code>

当然,我们仍然看不到我们的引号SVG,所以让我们着手解决这个问题。<svg></svg>组件接受一个src属性,该属性采用SVG元素的源代码。对此没有太多可说的,所以让我们保持简单,直接跳回代码:

<code>const leftQuotationSvgSrc = `<svg fill="none" height="103" viewbox="0 0 117 103" width="117" xmlns="<http://www.w3.org/2000/svg>">
  // 为简洁起见,已缩短
</svg>`;
const rightQuotationSvgSrc = `<svg fill="none" height="103" viewbox="0 0 118 103" width="118" xmlns="<http://www.w3.org/2000/svg>">
// 为简洁起见,已缩短
</svg>`;

function QuotesWidget() {
  return (
    <svg name="{" leftquotationmark src="%7BleftQuotationSvgSrc%7D"></svg><svg name="{" rightquotationmark src="%7BrightQuotationSvgSrc%7D"></svg>
  );
}</code>

我认为我们都可以同意现在一切都清楚多了!当我们命名事物时,它们的目的突然变得对我们代码的读者更加明显。

实时预览我们的Widget

Figma在构建小部件时提供了良好的开发体验,包括(但不限于)热重载。使用此功能,我们可以实时编码和预览对小部件的更改。

首先打开小部件菜单(Shift I),切换到开发选项卡,然后单击或拖动你的新小部件到画板。找不到你的小部件?别担心,只需单击三点菜单并导入你的小部件的manifest.json文件即可。是的,这就是让它恢复存在的全部步骤!

等等,你的屏幕底部是否出现错误消息?

如果是这样,让我们调查一下。单击“打开控制台”并阅读它的内容。如果“打开控制台”按钮消失了,则有一种替代方法可以打开调试控制台。单击Figma徽标,跳转到“小部件”类别并显示开发菜单。

该错误可能是因为我们尚未将TypeScript编译为JavaScript。我们可以通过运行npm installnpm run watch(或yarnyarn watch)在命令行中执行此操作。这次没有错误!

你可能会遇到的另一个障碍是,每次代码更改时,小部件都无法重新渲染。我们可以使用以下上下文菜单命令轻松强制小部件更新:小部件重新渲染小部件

样式设置小部件

就目前而言,我们小部件的外观仍然与我们的最终目标相差甚远。

那么我们如何从代码中设置Figma组件的样式呢?也许像在React项目中那样使用CSS?错误。对于Figma小部件,所有样式都是通过一套完善的属性来实现的。幸运的是,这些项目的名称与Figma中的对应项目几乎完全相同

我们将首先配置我们的两个<autolayout></autolayout>组件。如上图所示,属性名称对它们的目的进行了非常清晰的描述。这使我们能够直接跳转到代码并开始进行一些更改。我不会再次显示整个代码,所以请依靠组件名称来指导你代码片段的位置。

<code><autolayout direction="{" horizontal horizontal:="" horizontalalignitems="{" center name="{" quote padding="{{" spacing="{54}" vertical:="" verticalalignitems="{" start><autolayout direction="{" vertical horizontal:="" horizontalalignitems="{" start name="{" quotecontent padding="{{" spacing="{10}" vertical:="" verticalalignitems="{" end></autolayout></autolayout>;</code>

我们取得了很大的进展!让我们保存并跳回到Figma以查看我们的Widget的外观。还记得新更改后Figma如何自动重新加载Widget吗?

但它还不够。我们还必须向根组件添加背景颜色:

<code><autolayout fill="{" name="{" quote></autolayout></code>

同样,查看你的Figma画板,注意更改如何几乎立即反映到Widget中。

让我们继续本指南并设置<text></text>组件的样式。

查看Widgets API文档后,再次清楚地看到属性名称与其在Figma应用程序中的对应项几乎相同,如上图所示。我们还将使用上一节中检查Chris网站的值。

<code><text fill="{'#545454'}" fontfamily="{'Lora'}" fontsize="{36}" fontweight="{'normal'}" name="{'QuoteText'}" width="{700}">{quote}</text><text fill="{'#16B6DF'}" fontfamily="{'Raleway'}" fontsize="{26}" fontweight="{'bold'}" name="{'QuoteAuthor'}" textcase="{'upper'}" width="{700}">— {author}</text></code>

向Widget添加状态

我们的小部件目前显示相同的报价,但我们希望随机从整个报价池中提取。我们必须向我们的Widget添加状态,所有React开发人员都知道这是一个变量,它的更改会触发我们组件的重新渲染。

在Figma中,状态是使用useSyncedState钩子创建的;它几乎就是React的useState,但它要求程序员指定一个唯一的key。此要求源于这样一个事实,即Figma必须同步我们Widget的状态,这些状态跨越可能正在查看同一设计画板的所有客户端,但通过不同的计算机。

<code>const { useSyncedState } = widget;

function QuotesWidget() {
  const [quote, setQuote] = useSyncedState("quote-text", "");
  const [author, setAuthor] = useSyncedState("quote-author", "");
}</code>

目前,这就是我们需要做的全部更改。在下一节中,我们将弄清楚如何从互联网获取数据。剧透警告:这并不像看起来那么简单。

从网络获取数据

回想一下Figma让我们选择从启用iFrame的小部件开始。虽然我们没有选择该选项,但我们仍然必须实现其一些功能。让我解释一下为什么我们不能简单地在小部件代码中调用fetch()

当你使用小部件时,你正在你的计算机上运行由其他人编写的JavaScript代码。虽然所有小部件都经过Figma员工的彻底审查,但这仍然是一个巨大的安全漏洞,因为我们都知道即使是一行JavaScript也会造成多大的损害。

因此,Figma不能简单地eval()匿名程序员编写的任何小部件代码。长话短说,团队决定最佳解决方案是在严密保护的沙箱环境中运行第三方代码。正如你可能猜到的那样,浏览器API在这种环境中是不可用的。

但不要担心,Figma对此第二个问题的解决方案是<iframe></iframe>。我们在文件中编写的任何HTML代码(最好称为ui.html)都可以访问所有浏览器API。你可能想知道我们如何从Widget触发此代码,但我们稍后会研究这个问题。现在,让我们回到代码中:

<code>// manifest.json
{
  "ui": "ui.html"
}</code>
<code>

window.onmessage = async (event) => {
  if (event.data.pluginMessage.type === 'networkRequest') {
    // TODO: 从服务器获取数据

    window.parent.postMessage({
      pluginMessage: {
        // TODO: 返回获取的数据
      }
    }, '*')
  }
}
</code>

这是Widget到iFrame通信的通用模板。让我们用它从服务器获取数据:

<code>

window.onmessage = async (event) => {
  if (event.data.pluginMessage.type === 'networkRequest') {
    // 获取从0到100的随机数
    const randomPage = Math.round(Math.random() * 100)

    // 从Design Quotes API获取随机报价
    const res = await fetch(`https://quotesondesign.com/wp-json/wp/v2/posts/?orderby=rand&per_page=1&page=${randomPage}&_fields=title,yoast_head_json`)
    const data = await res.json()

    // 从响应中提取作者姓名和报价内容
    const authorName = data[0].title.rendered
    const quoteContent = data[0].yoast_head_json.og_description

    window.parent.postMessage({
      pluginMessage: {
        authorName,
        quoteContent
      }
    }, '*')
  }
}
</code>

为了保持简单明了,我们省略了错误处理。让我们回到小部件代码中,看看我们如何访问<iframe></iframe>中定义的函数:

<code>function fetchData() {
  return new Promise<void>(resolve => {
    figma.showUI(__html__, {visible: false})
    figma.ui.postMessage({type: 'networkRequest'})

    figma.ui.onmessage = async ({authorName, quoteContent}) => {
      setAuthor(authorName)
      setQuote(quoteContent)

      resolve()
    }
  })
}</void></code>

如你所见,我们首先告诉Figma公开访问我们隐藏的<iframe></iframe>并触发名为“networkRequest”的事件。我们通过检查event.data.pluginMessage.type === 'networkRequest'来处理ui.html文件中的此事件,然后将数据发布回小部件。

但是现在还没有发生任何事情……我们仍然没有调用fetchData()函数。如果我们直接在组件函数中调用它,则控制台中会出现以下错误:

<code>在小部件渲染期间无法使用showUI。</code>

Figma告诉我们不要直接在函数体中调用showUI……那么我们应该把它放在哪里呢?答案是一个新的钩子和一个新的函数:useEffectwaitForTask。如果你是一位React开发人员,你可能已经熟悉useEffect了,但我们将在这里使用它来在小部件组件挂载时从服务器获取数据。

<code>const { useEffect, waitForTask } = widget;

function QuotesWidget() {
  useEffect(() => {
    waitForTask(fetchData());
  });
}</code>

但这会导致另一个“错误”,我们的Widget将永远使用新的报价不断重新渲染。发生这种情况是因为useEffect根据定义,每当Widget的状态发生更改时,或者当我们调用fetchData时,它都会再次触发。虽然有一种技术可以在React中只调用一次useEffect,但它不适用于Figma的实现。来自Figma文档:

由于小部件的运行方式,useEffect应该处理使用相同状态多次被调用。

幸运的是,我们可以利用一个简单的解决方法,只在组件第一次挂载时调用一次useEffect,方法是检查状态的值是否仍然为空:

<code>function QuotesWidget() {
  useEffect(() => {
    if (!author.length & !quote.length) {
      waitForTask(fetchData());
    }
  });
}</code>

你可能会遇到一个可怕的“内存访问越界”错误。这在插件和小部件开发中非常常见。只需重新启动Figma,它就不会再出现了。

你可能已经注意到,有时报价文本包含奇怪的字符。

这些是Unicode字符,我们必须在代码中正确格式化它们:

<code>

window.onmessage = async (event) => {
  // ...
  const quoteContent = decodeEntities(data[0].yoast_head_json.og_description);
};

// <https:>
var decodeEntities = (function () {
  // this prevents any overhead from creating the object each time
  var element = document.createElement("div");

  function decodeHTMLEntities(str) {
    if (str && typeof str === "string") {
      // strip script/html tags
      str = str.replace(/]*>([\\\\S\\\\s]*?)/gim, "");
      str = str.replace(/]|"[^"]*"|'[^']*')*>/gim, "");
      element.innerHTML = str;
      str = element.textContent;
      element.textContent = "";
    }

    return str;
  }

  return decodeHTMLEntities;
})();
</https:></code>

瞧,我们的Widget每次添加到设计画板时都会获取一个全新的设计报价。

向我们的Widget添加属性菜单

虽然我们的Widget在实例化时会获取新的报价,但如果我们能够再次执行此过程而无需删除它,则会更实用。本节将简短介绍,因为解决方案非常出色。使用属性菜单,我们可以通过一次调用usePropertyMenu钩子来向我们的Widget添加交互性。

<code>const { usePropertyMenu } = widget;

function QuotesWidget() {
  usePropertyMenu(
    [
      {
        itemType: "action",
        propertyName: "generate",
    tooltip: "Generate",
        icon: `<svg fill="none" height="15" viewbox="0 0 22 15" width="22" xmlns="<http://www.w3.org/2000/svg>"></svg>`,
      },
    ],
    () => fetchData()
  );
}</code>

使用一个简单的钩子,我们就可以创建一个按钮,当选中我们的Widget时,该按钮会出现在我们的Widget附近。这是我们需要添加的最后一个部分才能完成这个项目。

将我们的Widget发布到公共

如果没有人使用它,那么构建Widget就没有多大用处。虽然Figma允许组织启动用于内部使用的私有Widget,但将这些小程序发布到世界各地更为常见。

Figma有一个细致的小部件审查流程,可能需要5到10个工作日。虽然我们一起构建的设计报价小部件已经位于小部件库中,但我仍然会演示它是如何到达那里的。请不要尝试再次发布此小部件,因为这只会导致删除。但是,如果你对其进行了一些重大更改,请继续与社区分享你自己的小部件!

首先单击小部件菜单(Shift I),然后切换到开发选项卡以查看我们的Widget。单击三点菜单并按发布

Figma会提示你输入有关你的Widget的一些详细信息,例如标题、描述和一些标签。我们还需要一个128×128的图标图像和一个1920×960的横幅图像。

导入所有这些资源后,我们仍然需要Widget的屏幕截图。关闭发布模式(别担心,你不会丢失数据),然后右键单击Widget以显示一个有趣的上下文菜单。找到复制/粘贴为类别并选择复制为PNG

完成此操作后,让我们回到发布模式并将Widget的屏幕截图粘贴进去:

向下滚动并最终发布你的模式。庆祝!?

Figma会在几天后与你联系,告知你的模式审查状态。如果被拒绝,你将有机会进行更改并再次提交。

结论

我们刚刚从头开始构建了一个Figma小部件!这里有很多内容没有涵盖,例如单击事件、输入表单等等。你可以在这个GitHub存储库中深入了解Widget的完整源代码。

对于那些渴望将他们的Figma技能提升到更高水平的人,我建议探索Widgets社区,并使用你感兴趣的内容作为灵感。继续构建更多的小部件,继续磨练你的React技能,在你意识到之前,你将教我如何做到这一切。

更多资源

在制作这个Widget时,我不得不参考大量的文档。我认为我会分享我发现最有帮助的内容。

构建更多小部件:

  • 构建小部件的最佳实践
  • 官方Figma小部件示例,包含代码

更深入地学习小部件:

  • 所有小部件钩子
  • 所有小部件组件
  • 小部件在幕后如何运行

小部件与插件

  • 小部件与插件
  • Figma插件简介
  • 插件在幕后如何运行

以上是构建互动无花果小部件的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
什么是CSS网格?什么是CSS网格?Apr 30, 2025 pm 03:21 PM

CSS网格是创建复杂,响应式Web布局的强大工具。它简化了设计,提高可访问性并提供了比旧方法更多的控制权。

什么是CSS Flexbox?什么是CSS Flexbox?Apr 30, 2025 pm 03:20 PM

文章讨论了CSS FlexBox,这是一种布局方法,用于有效地对齐和分布响应设计中的空间。它说明了FlexBox用法,将其与CSS网格进行了比较,并详细浏览了浏览器支持。

我们如何使用CSS使网站迅速响应?我们如何使用CSS使网站迅速响应?Apr 30, 2025 pm 03:19 PM

本文讨论了使用CSS创建响应网站的技术,包括视口元标签,灵活的网格,流体媒体,媒体查询和相对单元。它还涵盖了使用CSS网格和Flexbox一起使用,并推荐CSS框架

CSS盒装属性有什么作用?CSS盒装属性有什么作用?Apr 30, 2025 pm 03:18 PM

本文讨论了CSS盒装属性,该属性控制了元素维度的计算方式。它解释了诸如Content-Box,Border-Box和Padding-Box之类的值,以及它们对布局设计和形式对齐的影响。

我们如何使用CSS动画?我们如何使用CSS动画?Apr 30, 2025 pm 03:17 PM

文章讨论使用CSS,关键属性并与JavaScript结合创建动画。主要问题是浏览器兼容性。

我们可以使用CSS向我们的项目添加3D转换吗?我们可以使用CSS向我们的项目添加3D转换吗?Apr 30, 2025 pm 03:16 PM

文章讨论了Web项目的3D转换,关键属性,浏览器兼容性和性能注意事项的讨论。(角色计数:159)

我们如何在CSS中添加梯度?我们如何在CSS中添加梯度?Apr 30, 2025 pm 03:15 PM

文章讨论了使用CSS梯度(线性,径向,重复)来增强网站视觉效果,添加深度,焦点和现代美学。

CSS中的伪元素是什么?CSS中的伪元素是什么?Apr 30, 2025 pm 03:14 PM

文章讨论了CSS中的伪元素,它们在增强HTML样式方面的使用以及与伪级的差异。提供实用的例子。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

Dreamweaver Mac版

Dreamweaver Mac版

视觉化网页开发工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)