# 使用 React 后端渲染 SVG 图片
**Published by:** [Found Pan Tiger](https://paragraph.com/@aliez/)
**Published on:** 2021-10-21
**URL:** https://paragraph.com/@aliez/react-svg
## Content
这篇文章教你使用 Figma 作为设计工具,使用 React 作为模版渲染工具,使用 Next.js 作为 SSR,渲染出一个 SVG 图片。最近参与制作了即刻里的一个小功能“我的持仓”。其前端主要分为两部分:一部分是即刻个人主页下的“小卡片”,另一部分是点击小卡片后跳转到的网页。我们主要来讲讲这个小卡片是如何实现的。小卡片实际上是一张 SVG 图片,放在整个卡片列表中的一个
标签里为什么不以 SVG DOM 的方式渲染?这样做的话,卡片列表(上图黄框部分)和卡片内容(上图红框部分)代码要放在同一个项目中,“我的持仓”业务逻辑和即刻的业务逻辑就耦合了。为什么不用 PNG 图片?因为图片中含有文字,PNG 图片无法适配不同手机的不同字体。Figma 导出 SVG导出时注意不要勾选 Outline Text,该选项会把 text 变成 path,也就是把字体当作矢量图来画。但是在我们的渲染中需要 text 作为变量,因此不要勾选。React 渲染 SVGReact 本身就支持 SVG 渲染,把刚才导出的 svg 代码复制粘贴成为一个 React Componentexport const SvgBox = () => ( <svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" > ... </svg> ); Next.js SSR使用 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: {}, }; }; 之后所需要做的事情就是根据业务逻辑给 组件传入变量,就像写普通 React 组件一样。嵌入图片值得注意的是,为了在 Android 系统上显示 Apple Emoji,小卡片第二行行首的 emoji 不是字符,而是 PNG 图片。base64 encode在
标签里显示的 svg 不能再请求外部资源,所以我们需要把 PNG base64 encode 后作为 Data URL 传入 SVG 的 标签中,而不能只传一个 url。AVIF 和 WebPPNG 图片 base64 后体积太大了,因此我为每张 emoji PNG 都准备了对应的 AVIF 和 WebP 版本,根据 req.headers.accept 来给 SVG 嵌入不同格式的图片
## Publication Information
- [Found Pan Tiger](https://paragraph.com/@aliez/): Publication homepage
- [All Posts](https://paragraph.com/@aliez/): More posts from this publication
- [RSS Feed](https://api.paragraph.com/blogs/rss/@aliez): Subscribe to updates
- [Twitter](https://twitter.com/RenzHoly): Follow on Twitter