前言在《一篇带你用 VuePress + Github Pages 搭建博客》中,我们使用VuePress搭建了一个博客。查看最终效果:TypeScript中文文档。如果我们浏览过TypeScript官方文档,我们会发现一个非常有用的功能,就是很多代码块,悬停时会出现一个Try按钮:点击跳转到对应的Playground,如图所示按钮的跳转就是这个链接,我们可以在这个Playground中修改验证代码效果。如果我们要实现这样的功能,应该怎么实现呢?想一想,我们很容易想到写一个VuePress插件来实现,这个效果看起来有点像代码复制插件,但是仔细想想,并不是这样的。代码复制插件的实现可以参考《从零实现一个 VuePress 插件》。页面渲染完成后,可以遍历每个代码块,插入一个复制按钮。点击复制时,代码会写入剪贴板,只是代码块的跳转不同。是的,代码跳转需要我们先写一个链接地址,然后渲染按钮。问题是链接地址写在哪里?要知道,我们能写的只是一个普通的markdown文件。。。于是我们就想,有没有可能把markdown的语法扩展一下?比如正常的代码块写法是:```typescriptconstmessage="HelloWorld!";```为了达到这个效果,我们是不是可以这样写:```typescript//try-link:https://www.baidu.comconstmessage='HelloWorld!';```但是在渲染的时候,一行注释try-link并没有渲染出来,而是变成了这样的效果:点击Try的时候,跳转到对应的链接。当然,如果效果更好,只有当鼠标悬停在代码块上时才能显示Try按钮,类似这样的效果:markdown-it查阅VuePress的官方文档,我们可以知道:VuePress使用markdown-it来渲染Markdown,什么是markdown-it?查看markdown-it的Github仓库,可以看到这个介绍:Markdownparserdoneright。快速且易于扩展。简单的说,markdown——它是一个markdown渲染器,可以将markdown渲染成html等,markdown——它支持编写插件来扩展功能。其实,为什么VuePress项目中的markdown文件可以支持编写Vue组件,是因为VuePress编写了支持Vue语法的插件。我们是否也可以扩展markdown的语法?幸运的是,在VuePress的文档中,提供了自定义markdown-it插件的配置:VuePress使用markdown-it(opensnewwindow)来渲染Markdown,而上述大部分扩展也是通过自定义插件实现的。如果你想更进一步,你可以使用.vuepress/config.js中的markdown选项为当前的markdown-it实例做一些自定义配置:module.exports={markdown:{//markdown-it-anchoroptionsanchor:{permalink:false},//markdown-it-toc的选项toc:{includeLevel:[1,2]},extendMarkdown:md=>{//使用更多的markdown-it插件!md.use(require('markdown-it-xxx'))}}}引入的方法是知道的,但是这个markdown-it插件怎么写呢?markdown-it插件参考了markdown-it的Github仓库代码和文档,我们可以大致了解markdown-it的工作原理。它的转换过程类似于Babel。它首先被转化为抽象语法树,然后生成相应的代码。简单总结分为两个过程:Parse和Render。我们通过查看源码也可以看出这一点:MarkdownIt.prototype.render=function(src,env){env=env||{};返回this.renderer.render(this.parse(src,env),this.options,env);};所以这里我们有两种解决问题的思路,一种是在Parse进程中处理,一种是在Render进程中处理。为了简单起见,我决定直接处理Render过程,查看Render的源码。我们可以看到Render中已经按照一些固定的类型写好了defaultRules(渲染规则),比如about代码块:default_rules.fence=function(tokens,idx,options,env,slf){vartoken=tokens[idx],信息=token.info?unescapeAll(token.info).trim():'',langName='',langAttrs='',突出显示,i,arr,tmpAttrs,tmpToken;如果(信息){//...}if(options.highlight){highlighted=options.highlight(token.content,langName,langAttrs)||escapeHtml(token.content);}else{highlighted=escapeHtml(token.content);}if(highlighted.indexOf('
'+highlighted+'\n';};我们可以重写这个规则,参考markdown-it提供的插件编写原则,我们可以这样写:自己){//...};为了省事一点,我准备直接获取最终渲染出来的HTML结果,是一个字符串,然后匹配//try-link:xxx生成的HTML,换成一个链接,让我们检查注释生成的HTML//try-link:xxx:修改config.js文件:module.exports={markdown:{extendMarkdown:md=>{md.use(function(md){constfence=md.renderer.rules.fencemd.renderer.rules.fence=(...args)=>{letrawCode=fence(...args);rawCode=rawCode.replace(/\/\/尝试链接https:\/\/(.*)<\/span>\n/ig,'尝试 ');return`${rawCode}`}})}}}这里为了简洁,没有直接把链接的样式写成inline,而是加了一个类之后,写在哪里这堂课的风格?VuePress提供了docs/.vuepress/styles/index.styl文件作为会自动应用的全局样式文件,在最终的CSS文件末尾生成,优先级高于默认样式所以我们在index.styl文件下写样式://defaultstyle.try-button{position:absolute;底部:1em;右:1em;字体粗细:100;边框:1px实心#719af4;边界半径:4px;颜色:#719af4;填充:2px8px;文字修饰:无;过渡计时功能:轻松;过渡:不透明度.3s;opacity:0;}//hoverstyle.content__default:not(.custom)a.try-button:hover{background-color:#719af4;颜色:#fff;text-decoration:none;}有时候自动编译可能没有生效,我们可以重新运行yarnrundocs:dev。此时按钮可以正常显示了(默认样式透明度为0,此处截图强行设置透明度为1):接下来我们需要实现的是只有当鼠标悬停在代码块。这里我们可以使用中的方法获取页面挂载时所有的代码块元素,然后添加事件,然后我们修改config.js文件:module.exports={plugins:[(options,ctx)=>{return{name:'vuepress-plugin-code-try',clientRootMixin:path.resolve(__dirname,'vuepress-plugin-code-try/index.js')}}],markdown:{extendMarkdown:md=>{md.use(function(md){constfence=md.renderer.rules.fencemd.renderer.rules.fence=(...args)=>{letrawCode=fence(...args);rawCode=rawCode.replace(/\/\/尝试链接https:\/\/(.*)<\/span>\n/ig,'Try ');return`${rawCode}`}})}}}然后在同级目录下创建vuepress-plugin-code-try目录config.js,然后新建一个index.js文件:exportdefault{mounted(){setTimeout(()=>{document.querySelectorAll('div[class*="language-"]pre').forEach(el=>{if(el.querySelector('.try-button')){el.addEventListener('mouseover',()=>{el.querySelector('.try-button').style.opacity='1';})el.addEventListener('mouseout',()=>{el.querySelector('.try-button').style.opacity='0';})}})},100)}}此时,再次运行项目,我们就达到了原来想要的效果:系列文章博客搭建系列是我目前为止唯一写的实用系列教程,讲解如何使用VuePress搭建博客,并部署到GitHub、Gitee、个人服务器等平台。一会带你用VuePress+GitHubPages搭建博客。一个会教你如何在GitHub和Gitee之间同步代码。无法使用GitHubActions?看看这个Gitee是如何自动部署Pages的?仍然使用GitHubActions!一个前端足够用的Linux命令一个足够简单的NginxLocation配置说明从购买服务器到部署博客代码的详细教程从域名购买到备案到解析的详细教程VuePress博客优化最后更新最后更新时间如何设置VuePress博客优化添加统计功能VuePress博客优化启用HTTPSVuePress博客优化启用Gzip压缩从头开始实现一个VuePress插件微信:“mqyqingfeng”,加我到SaeYu的唯一读者群。如有错误或不准确的地方,请务必指正,万分感谢。如果你喜欢或者有启发,欢迎star,这也是对作者的鼓励。