如何在NextJS 13中添加带可点击<a>标签的SVG组件?
解决Next.js中SVGR加载SVG内标签无法点击的问题
问题场景
在Next.js v13.4.2中使用SVGR v8.1.0加载SVG时,SVG内部的<a>标签无法触发点击跳转,相关代码如下:
SVG文件内容
<svg height='50'> <a href='#'><text x='0' y='20'>click in svg</text> </a> </svg>
页面组件代码
import './globals.css' import Vercel from '../public/vercel.svg' export default function Home() { return ( <main> <div> Hello World <Vercel /> </div> </main> ) }
Next.js Webpack配置(next.config.js)
/** @type {import('next').NextConfig} */ const nextConfig = { webpack(config) { // 配置webpack通过SVGR处理SVG文件 const fileLoaderRule = config.module.rules.find((rule) => rule.test?.test?.('.svg')); config.module.rules.push( // 针对带?url后缀的SVG使用原file-loader规则 { ...fileLoaderRule, test: /\.svg$/i, resourceQuery: /url/, }, // 其他SVG通过SVGR转换为React组件 { test: /\.svg$/i, issuer: fileLoaderRule.issuer, resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] }, use: ['@svgr/webpack'], } ); fileLoaderRule.exclude = /\.svg$/i; return config; }, } module.exports = nextConfig
解决方案
1. 配置SVGR保留原生SVG元素
SVGR默认会将SVG中的<a>标签转换为React的<a>组件,可能导致跳转行为异常。修改Webpack规则,添加native: true选项强制保留原生SVG元素:
// 修改next.config.js中的SVGR规则部分 { test: /\.svg$/i, issuer: fileLoaderRule.issuer, resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] }, use: [ { loader: '@svgr/webpack', options: { native: true, // 保留原生SVG标签,不转换为React组件 }, }, ], }
2. 手动处理SVG跳转逻辑
如果上述配置无效,可以采用以下两种方式:
- 直接嵌入SVG代码:将SVG内容直接写入React组件,绕过SVGR转换:
export default function Home() { return ( <main> <div> Hello World <svg height='50'> <a href='#'><text x='0' y='20'>click in svg</text></a> </svg> </div> </main> ) }
- 添加点击事件模拟跳转:给导入的SVG组件绑定
onClick事件,手动触发跳转:
import Vercel from '../public/vercel.svg' export default function Home() { const handleSvgClick = () => { window.location.href = '#'; }; return ( <main> <div> Hello World <Vercel onClick={handleSvgClick} style={{ cursor: 'pointer' }} /> </div> </main> ) }
3. Next.js渲染纯HTML的方式
Next.js支持通过dangerouslySetInnerHTML渲染纯HTML内容,但该方式存在XSS风险,仅在必要时使用:
export default function Home() { const svgHtml = ` <svg height='50'> <a href='#'><text x='0' y='20'>click in svg</text></a> </svg> `; return ( <main> <div> Hello World <div dangerouslySetInnerHTML={{ __html: svgHtml }} /> </div> </main> ) }
内容的提问来源于stack exchange,提问作者nhuluseda
相关产品推荐
相关产品推荐

