这篇文章教你使用 Figma 作为设计工具,使用 React 作为模版渲染工具,使用 Next.js 作为 SSR,渲染出一个 SVG 图片。
最近参与制作了即刻里的一个小功能“我的持仓”。其前端主要分为两部分:一部分是即刻个人主页下的“小卡片”,另一部分是点击小卡片后跳转到的网页。我们主要来讲讲这个小卡片是如何实现的。
<img />
标签里导出时注意不要勾选 Outline Text
,该选项会把 text 变成 path,也就是把字体当作矢量图来画。但是在我们的渲染中需要 text 作为变量,因此不要勾选。
React 本身就支持 SVG 渲染,把刚才导出的 svg 代码复制粘贴成为一个 React Component
export const SvgBox = () => (
<svg
width="100"
height="100"
viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg"
>
...
</svg>
);
使用 Next.js 的约定式路由,新建一个页面文件,使用 renderToStaticMarkup 和 getServerSideProps 进行服务端渲染。请求这个页面时,返回的是 SVG,而不是 HTML。
import type { GetServerSideProps } from "next";
import { renderToStaticMarkup } from "react-dom/server";
export default function SvgPage() {
return null;
}
export const getServerSideProps: GetServerSideProps = async ({ res }) => {
res.setHeader("Content-Type", "image/svg+xml");
res.write(renderToStaticMarkup(<SvgBox />));
res.end();
return {
props: {},
};
};
之后所需要做的事情就是根据业务逻辑给 <SvgBox />
组件传入变量,就像写普通 React 组件一样。
值得注意的是,为了在 Android 系统上显示 Apple Emoji,小卡片第二行行首的 emoji 不是字符,而是 PNG 图片。
在 <img />
标签里显示的 svg 不能再请求外部资源,所以我们需要把 PNG base64 encode 后作为 Data URL 传入 SVG 的 <image />
标签中,而不能只传一个 url。
PNG 图片 base64 后体积太大了,因此我为每张 emoji PNG 都准备了对应的 AVIF 和 WebP 版本,根据 req.headers.accept
来给 SVG 嵌入不同格式的图片