如何实现元素悬停时显示内容并替换为Lucide图标
实现GitHub风格标题悬停显示图标效果
问题
当前使用rehype-autolink-headings的wrap模式为标题添加锚点,通过CSS的::after伪元素显示#符号,但该符号始终可见。需要实现仅在标题悬停时显示图标,并将#替换为lucide-react的图标。
解决方案
方法1:纯CSS实现(无需修改React组件)
直接通过CSS伪元素和悬停状态控制图标显示,使用Lucide图标的SVG Data URI作为内容:
/* 锚点容器样式,确保图标对齐 */ .section_heading { position: relative; display: inline-flex; align-items: center; } /* 默认隐藏图标 */ .section_heading::after { content: ""; /* Lucide Hash图标SVG Data URI,可替换为其他图标 */ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='4' y1='9' x2='20' y2='9'%3E%3C/line%3E%3Cline x1='4' y1='15' x2='20' y2='15'%3E%3C/line%3E%3Cline x1='10' y1='3' x2='8' y2='21'%3E%3C/line%3E%3Cline x1='16' y1='3' x2='14' y2='21'%3E%3C/line%3E%3C/svg%3E"); width: 16px; height: 16px; margin-left: 8px; opacity: 0; transition: opacity 0.2s ease; } /* 悬停时显示图标 */ .section_heading:hover::after { opacity: 1; }
方法2:自定义MDX组件实现(支持React特性)
通过自定义MDX标题组件插入Lucide图标,用Tailwind的group类控制悬停显示,适合需要动态调整图标的场景:
- 导入Lucide图标
import { Hash } from 'lucide-react';
- 自定义标题组件
const components = useMDXComponents({ h1: (props) => ( <h1 {...props} className="group"> {props.children} <Hash className="ml-2 opacity-0 group-hover:opacity-100 transition-opacity" size={16} /> </h1> ), h2: (props) => ( <h2 {...props} className="group"> {props.children} <Hash className="ml-2 opacity-0 group-hover:opacity-100 transition-opacity" size={16} /> </h2> ), h3: (props) => ( <h3 {...props} className="group"> {props.children} <Hash className="ml-2 opacity-0 group-hover:opacity-100 transition-opacity" size={14} /> </h3> ), // 按需添加h4、h5、h6组件 });
完整代码示例
import remarkGfm from 'remark-gfm'; import rehypeSlug from 'rehype-slug'; import rehypeAutolinkHeadings from "rehype-autolink-headings"; import { Hash } from 'lucide-react'; type Params = { params: { slug: string; }; }; export default async function PostPage({ params }: Params) { const source = await getPostBySlug(params.slug); // 自定义MDX标题组件,添加悬停图标 const components = useMDXComponents({ h1: (props) => ( <h1 {...props} className="group"> {props.children} <Hash className="ml-2 opacity-0 group-hover:opacity-100 transition-opacity" size={16} /> </h1> ), h2: (props) => ( <h2 {...props} className="group"> {props.children} <Hash className="ml-2 opacity-0 group-hover:opacity-100 transition-opacity" size={16} /> </h2> ), h3: (props) => ( <h3 {...props} className="group"> {props.children} <Hash className="ml-2 opacity-0 group-hover:opacity-100 transition-opacity" size={14} /> </h3> ), }); const { content, frontmatter } = await compileMDX<{ title: string, subtitle: string, part: string }>({ source: source, components: components, options: { parseFrontmatter: true, mdxOptions: { remarkPlugins: [remarkGfm], rehypePlugins: [ rehypeSlug, [rehypeAutolinkHeadings, { behaviour: "wrap", properties: { className: ['section_heading'], }, }] ] } }, }); return ( <article className="px-4 sm:px-6 md:px-8"> <div className="relative max-w-3xl mx-auto"> <div className="prose prose-lg prose-p:mb-2 text-justify dark:prose-invert max-w-3xl"> <div className="prose-strong:text-gray-900 dark:prose-em:text-slate-400 dark:prose-strong:text-slate-400 prose-em:text-gray-900"> {content} </div> </div> </div> </article> ); }
内容的提问来源于stack exchange,提问作者Rasik
相关产品推荐
相关产品推荐

