当前位置: 首页 > Web前端 > vue.js

从零开始实现一个VuePress插件

时间:2023-04-01 02:06:04 vue.js

.code-copy-btn{position:absolute;底部:10px;右:7.5px;不透明度:0.75;游标:指针;font-size:14px;}.code-copy-btn:hover{opacity:1;}前言在《一篇带你用 VuePress + Github Pages 搭建博客》中,我们使用VuePress搭建了一个博客,看看最终效果:TypeScript中文文档。但是在搭建VuePress博客的过程中,并不是所有的插件都能满足需求,所以本文将以代码复制插件的实现为例,教大家如何实现一个VuePress插件——从头开始。本地开发开发插件首先要解决的问题就是如何在本地进行开发。我们查看了VuePress1.0官方文档的“开发插件”部分,没有找到解决方案,但是在VuePress2.0官方文档的“本地插件”中,有写到:建议你直接使用配置文件作为插件,因为几乎所有的插件API都可以在配置文件中使用,这在大多数场景下更加方便。但是如果你在配置文件中要做的事情太多,最好将它们提取到单独的插件中,然后通过设置绝对路径或通过require:module.exports={plugins:[path.resolve(__dirname,'./path/to/your-plugin.js'),require('./another-plugin'),],}让我们开始吧!初始化项目我们在.vuepress文件夹下创建一个vuepress-plugin-code-copy文件夹,用来存放插件相关的代码,然后用命令行进入该文件夹,执行npminit,创建package.json。当前文件目录为:.vuepress├─vuepress-plugin-code-copy│└─package.json└─config.js我们在vuepress-plugin-code-copy下新建一个index.js文件,参考官方文档插件示例在写法上,我们使用返回对象的函数形式。该函数接受插件的配置选项作为第一个参数,包含编译时上下文的ctx对象作为第二个参数:module.exports=(options,ctx)=>{return{//...}}参考官方文档OptionAPI中的名称和生命周期函数中的readyhook,我们编写一个初始测试代码:module.exports=(options,ctx)=>{return{name:'vuepress-plugin-code-copy',asyncready(){console.log('HelloWorld!');}}}现在我们运行yarnrundocs:dev,在运行过程中可以看到我们的插件名称和打印结果:plug-indesign现在我们可以想象一下我们代码复制插件的效果,效果我想要实现的是:代码块右下角有个Copytext按钮,点击后文本变为Copied!然后一秒钟后,文本再次变为复制,代码单击时,块中的代码将复制到剪贴板。预期效果如下:如果在Vue组件中进行插件开发,我们可以轻松实现这种效果。当挂载或更新根组件时,使用document.querySelector获取所有代码块,插入一个按钮元素,然后在按钮元素上绑定一个点击事件。当点击事件被触发时,代码被复制到剪贴板,然后修改文本。1s后,修改文本VuePress插件有办法控制根组件的生命周期吗?我们查看了VuePress官方文档的OptionAPI,发现VuePress提供了一个clientRootMixin方法:mixin文件的路径,可以控制根组件的生命周期。示例代码见://插件入口constpath=require('path')module.exports={clientRootMixin:path.resolve(__dirname,'mixin.js')}//mixin.jsexportdefault{created(){},mounted(){}}这不是我们需要的吗?那我们动手吧,修改index.js的内容:constpath=require('path');module.exports=(options,ctx)=>{return{name:'vuepress-plugin-code-copy',clientRootMixin:path.resolve(__dirname,'clientRootMixin.js')}}在vuepress-plugin-code-copy下新建clientRootMixin.js文件,写代码:exportdefault{updated(){setTimeout(()=>{document.querySelectorAll('div[class*="language-"]pre').forEach(el=>{console.log('onecodeblock')})},100)}}在浏览器中刷新页面,然后看打印:接下来就是想怎么写到按钮元素上了。当然我们可以稍微使用原生的JavaScript创建元素,然后将其插入,但是我们实际上是在一个支持Vue语法的项目中,其实我们可以创建一个Vue组件,然后挂载该组件的实例到元素。那么用什么方法挂载呢?我们可以在Vue的全局API中找到Vue.extendAPI,看一下使用示例://elementtobemounted

//createconstructorvarProfile=Vue.extend({template:'

{{firstName}}{{lastName}}aka{{alias}}

',data:function(){return{firstName:'Walter',lastName:'White',alias:'Heisenberg'}}})//创建一个配置文件实例并将其附加到一个元素。newProfile().$mount('#mount-point')的结果如下://结果是:

WalterWhiteakaHeisenberg

接下来,我们创建一个Vue组件,然后通过Vue.extend方法,附加到每个代码块元素。在vuepress-plugin-code-copy下新建一个CodeCopy.vue文件,写入代码如下:.code-copy-btn{position:absolute;底部:10px;右:7.5px;不透明度:0.75;游标:指针;font-size:14px;}.code-copy-btn:hover{opacity:1;}该组件实现了按钮的样式和点击时的效果,将代码写入截版,整体代码比较简单,就不多描述了让我们修改clientRootMixin.js:"language-"]pre').forEach(el=>{//防止重复写入if(el.classList.contains('code-copy-added'))returnletComponentClass=Vue.extend(CodeCopy)letinstance=newComponentClass()instance.code=el.innerTextinstance.$mount()el.classList.add('code-copy-added')el.appendChild(instance.$el)})},100)}}有这里需要注意两点。首先是我们通过el.innerText获取要复制的代码内容,然后写入到实例的code属性中。在组件中,我们通过this.code获取。二是我们没有使用$mount(element),直接传入一个要挂载的节点元素。这是因为$mount()的挂载会清空目标元素,而这里我们需要将其添加到元素中,所以我们在执行instance.$mount()后,通过instance.$el获取实例元素,然后将appendChild添加到每个代码块。$el的使用请参考官方文档el章节。此时,我们的文件目录如下:.vuepress├─vuepress-plugin-code-copy│├─CodeCopy.vue│├─clientRootMixin.js│├─index.js│└─package.json└─config。这里的js,其实我们已经实现了代码重复的功能。插件选项有时,为了增加插件的可扩展性,允许配置选项。比如我们不希望按钮的文字是Copy,而是中文的“copy”。复制后,文字变成“已复制!”,如何实现?前面说过,我们index.js导出的函数第一个参数是options参数:constpath=require('path');module.exports=(options,ctx)=>{return{name:'vuepress-plugin-code-copy',clientRootMixin:path.resolve(__dirname,'clientRootMixin.js')}}我们先在config中写好需要的选项.js:module.exports={plugins:[[require('./vuepress-plugin-code-copy'),{'copybuttonText':'Copy','copiedButtonText':'复制!'}]]}我们可以通过index.js中的options参数接收我们在config.js中编写的选项,但是我们如何将这些参数传递到CodeCopy.vue文件中呢?我们看一下VuePress提供的OptionAPI,可以发现有一个defineAPI。其实这个define属性就是定义我们插件内部使用的全局变量。让我们修改index.js:constpath=require('path');module.exports=(options,ctx)=>{return{name:'vuepress-plugin-code-copy',define:{copybuttonText:选项。复制按钮文字||'复制',copiedButtonText:options.copiedButtonText||“抄袭了!”},clientRootMixin:path.resolve(__dirname,'clientRootMixin.js')}}现在我们已经写了两个全局变量,在组件使用中会发生什么?答案是直接用!让我们修改CodeCopy.vue的代码://...//...最终效果如下:代码参考完整代码查看:https://github.com/mqyqingfeng/Blog/tree/master/demos/VuePress/vuepress-plugin-code-copy其实本文的代码是指VuepressCodeCopyPlugin插件的代码。点击查看系列文章源地址。博客搭建系列是我目前为止写的唯一实用系列教程。讲解如何使用VuePress搭建博客并部署到GitHub、Gitee、个人服务器等平台。一会带你用VuePress+GitHubPages搭建博客一会教你如何在GitHub和Gitee之间同步代码还是不知道如何使用GitHubActions?看看这个Gitee是如何自动部署Pages的?仍然使用GitHubActions!前端够用的Linux命令足够简单的NginxLocation配置说明从购买服务器到部署博客代码的详细教程从域名购买到备案到解析的详细教程VuePress博客优化最后更新最后更新时间如何设置VuePress博客优化增加数据统计功能VuePress博客优化开启HTTPSVuePress博客优化开启Gzip压缩微信:“mqyqingfeng”,加我到SaeYu唯一读者群。如有错误或不准确的地方,请务必指正,万分感谢。如果你喜欢或者有启发,欢迎star,这也是对作者的鼓励。