成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網
最全最豐富的資訊網站

【VuePress實戰】手把手帶你開發一個代碼復制插件

本篇文章帶大家了解一下VuePress實戰,介紹一下如果從零開發一個 VuePress 插件(代碼復制插件),希望對大家有所幫助!

【VuePress實戰】手把手帶你開發一個代碼復制插件

在搭建 VuePress 博客的過程中,也并不是所有的插件都能滿足需求,所以本篇我們以實現一個代碼復制插件為例,教大家如何從零實現一個 VuePress 插件。

本地開發

開發插件第一個要解決的問題就是如何本地開發,我們查看 VuePress 1.0 官方文檔的「開發插件」章節,并沒有找到解決方案,但在 VuePress 2.0 官方文檔的「本地插件」里,卻有寫道:

推薦你直接將 配置文件 作為插件使用,因為幾乎所有的插件 API 都可以在配置文件中使用,這在絕大多數場景下都更為方便。

但是如果你在配置文件中要做的事情太多了,最好還是將它們提取到單獨的插件中,然后通過設置絕對路徑或者通過 require 來使用它們:

module.exports = {   plugins: [     path.resolve(__dirname, './path/to/your-plugin.js'),     require('./another-plugin'),   ], }

那就讓我們開始吧!

初始化項目

我們在 .vuepress 文件夾下新建一個 vuepress-plugin-code-copy 的文件夾,用于存放插件相關的代碼,然后命令行進入到該文件夾,執行 npm init,創建 package.json,此時文件的目錄為:

.vuepress ├─ vuepress-plugin-code-copy  │  └─ package.json └─ config.js

我們在 vuepress-plugin-code-copy下新建一個 index.js 文件,參照官方文檔插件示例中的寫法,我們使用返回對象的函數形式,這個函數接受插件的配置選項作為第一個參數、包含編譯期上下文的 ctx 對象作為第二個參數:

module.exports = (options, ctx) => {    return {       // ...    } }

再參照官方文檔 Option API 中的 name,以及生命周期函數中的 ready 鉤子,我們寫一個初始的測試代碼:

module.exports = (options, ctx) => {     return {         name: 'vuepress-plugin-code-copy',         async ready() {             console.log('Hello World!');         }     }  }

此時我們運行下 yarn run docs:dev,可以在運行過程中看到我們的插件名字和打印結果:

【VuePress實戰】手把手帶你開發一個代碼復制插件

插件設計

現在我們可以設想下我們的代碼復制插件的效果了,我想要實現的效果是:

在代碼塊的右下角有一個 Copy 文字按鈕,點擊后文字變為 Copied!然后一秒后文字重新變為 Copy,而代碼塊里的代碼則在點擊的時候復制到剪切板中,期望的表現效果如下:

【VuePress實戰】手把手帶你開發一個代碼復制插件

插件開發

如果是在 Vue 組件中,我們很容易實現這個效果,在根組件 mounted 或者 updated的時候,使用 document.querySelector獲取所有的代碼塊,插入一個按鈕元素,再在按鈕元素上綁定點擊事件,當觸發點擊事件的時候,代碼復制到剪切板,然后修改文字,1s 后再修改下文字。

那 VuePress 插件有方法可以控制根組件的生命周期嗎?我們查閱下 VuePress 官方文檔的 Option API,可以發現 VuePress 提供了一個 clientRootMixin 方法:

指向 mixin 文件的路徑,它讓你可以控制根組件的生命周期

看下示例代碼:

// 插件的入口 const path = require('path')  module.exports = {   clientRootMixin: path.resolve(__dirname, 'mixin.js') }
// mixin.js export default {   created () {},   mounted () {} }

這不就是我們需要的嗎?那我們動手吧,修改 index.js的內容為:

const path = require('path');  module.exports = (options, ctx) => {     return {         name: 'vuepress-plugin-code-copy',         clientRootMixin: path.resolve(__dirname, 'clientRootMixin.js')     }  }

vuepress-plugin-code-copy下新建一個 clientRootMixin.js文件,代碼寫入:

export default {     updated() {         setTimeout(() => {             document.querySelectorAll('div[class*="language-"] pre').forEach(el => { 								console.log('one code block')             })         }, 100)     } }

刷新下瀏覽器里的頁面,然后查看打印:

【VuePress實戰】手把手帶你開發一個代碼復制插件

接下來就要思考如何寫入按鈕元素了。

當然我們可以使用原生 JavaScript 一點點的創建元素,然后插入其中,但我們其實是在一個支持 Vue 語法的項目里,其實我們完全可以創建一個 Vue 組件,然后將組件的實例掛載到元素上。那用什么方法掛載呢?

我們可以在 Vue 的全局 API 里,找到 Vue.extendAPI,看一下使用示例:

// 要掛載的元素 <div id="mount-point"></div>
// 創建構造器 var Profile = Vue.extend({   template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',   data: function () {     return {       firstName: 'Walter',       lastName: 'White',       alias: 'Heisenberg'     }   } }) // 創建 Profile 實例,并掛載到一個元素上。 new Profile().$mount('#mount-point')

結果如下:

// 結果為: <p>Walter White aka Heisenberg</p>

那接下來,我們就創建一個 Vue 組件,然后通過 Vue.extend 方法,掛載到每個代碼塊元素中。

vuepress-plugin-code-copy下新建一個 CodeCopy.vue 文件,寫入代碼如下:

<template>     <span class="code-copy-btn" @click="copyToClipboard">{{ buttonText }}</span> </template>  <script> export default {     data() {         return {             buttonText: 'Copy'         }     },     methods: {         copyToClipboard(el) {             this.setClipboard(this.code, this.setText);         },         setClipboard(code, cb) {             if (navigator.clipboard) {                 navigator.clipboard.writeText(code).then(                     cb,                     () => {}                 )             } else {                 let copyelement = document.createElement('textarea')                 document.body.appendChild(copyelement)                 copyelement.value = code                 copyelement.select()                 document.execCommand('Copy')                 copyelement.remove()                 cb()             }         },         setText() {             this.buttonText = 'Copied!'              setTimeout(() => {                 this.buttonText = 'Copy'             }, 1000)         }     } } </script>  <style scoped> .code-copy-btn {     position: absolute;     bottom: 10px;     right: 7.5px;     opacity: 0.75;     cursor: pointer;     font-size: 14px; }  .code-copy-btn:hover {     opacity: 1; } </style>

該組件實現了按鈕的樣式和點擊時將代碼寫入剪切版的效果,整體代碼比較簡單,就不多敘述了。

我們修改一下 clientRootMixin.js

import CodeCopy from './CodeCopy.vue' import Vue from 'vue'  export default {     updated() {         // 防止阻塞         setTimeout(() => {             document.querySelectorAll('div[class*="language-"] pre').forEach(el => {               	// 防止重復寫入                 if (el.classList.contains('code-copy-added')) return                 let ComponentClass = Vue.extend(CodeCopy)                 let instance = new ComponentClass()                 instance.code = el.innerText                 instance.$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,而是中文的「復制」,復制完后,文字變為 「已復制!」,該如何實現呢?

前面講到,我們的 index.js導出的函數,第一個參數就是 options 參數:

const path = 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': '復制',           'copiedButtonText': '已復制!'         }       ]     ] }

我們 index.js中通過 options參數可以接收到我們在 config.js 寫入的選項,但我們怎么把這些參數傳入 CodeCopy.vue 文件呢?

我們再翻下 VuePress 提供的 Option API,可以發現有一個 define API,其實這個 define 屬性就是定義我們插件內部使用的全局變量。我們修改下 index.js

const path = require('path');  module.exports = (options, ctx) => {     return {         name: 'vuepress-plugin-code-copy',         define: {             copybuttonText: options.copybuttonText || 'copy',             copiedButtonText: options.copiedButtonText || "copied!"         },         clientRootMixin: path.resolve(__dirname, 'clientRootMixin.js')     }  }

現在我們已經寫入了兩個全局變量,組件里怎么使用呢?答案是直接使用!

我們修改下 CodeCopy.vue 的代碼:

// ... <script> export default {     data() {         return {             buttonText: copybuttonText         }     },     methods: {         copyToClipboard(el) {             this.setClipboard(this.code, this.setText);         },         setClipboard(code, cb) {             if (navigator.clipboard) {                 navigator.clipboard.writeText(code).then(                     cb,                     () => {}                 )             } else {                 let copyelement = document.createElement('textarea')                 document.body.appendChild(copyelement)                 copyelement.value = code                 copyelement.select()                 document.execCommand('Copy')                 copyelement.remove()                 cb()             }         },         setText() {             this.buttonText = copiedButtonText              setTimeout(() => {                 this.buttonText = copybuttonText             }, 1000)         }     } } </script> // ...

最終的效果如下:

【VuePress實戰】手把手帶你開發一個代碼復制插件

代碼參考

完整的代碼查看:https://github.com/mqyqingfeng/Blog/tree/master/demos/VuePress/vuepress-plugin-code-copy

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
中文字幕亚洲无线码在线一区| 中文字幕爆乳巨爆乳系列无码 | 欧美黑人又大又粗XXXX| 人妻夜夜爽天天爽三区| 四虎永久在线精品免费网址| 小鲜肉洗澡时自慰网站XNXX| 亚洲男同GV在线观看| 综合 欧美 小说 另类 图| 啊灬啊灬啊灬快灬高潮少妇软件| 成人免费无遮挡无码黄漫视频| 国产精品久久精品国产| 精品人妻系列无码人妻免费视频| 美女高潮无遮挡喷水视频| 人妻天天爽夜夜爽精品视频| 无码人妻久久一区二区三区免费| 亚洲乱码国产一区三区| 45歳の▽バツ1熟女とハメ撮り| 草莓 丝瓜 香蕉 向日葵 榴莲| 国产精品视频免费一区二区| 久久精品国产亚洲AV水果派| 欧美最猛黑人XXXXX猛交| 无码高潮爽到爆的喷水视频| 亚洲无人区码一二三四区别| XXXX日本少妇做受| 国产亚洲成AV人片在线观看导航 | А√天堂资源在线官网| 国产精品美女久久久网站动漫| 精品无码人妻一区二区三区18 | 新CHINESE无套小帅KTV| 中国A级毛片免费| 纯肉无遮挡H肉动漫在线观看3D| 孩子玩着玩着就进去了怎么回事| 免费无码AV片在线观看潮喷| 天天影视性色香欲综合网| 亚洲制服丝袜无码AV在线| 宝宝腿趴开一点就不会疼的原因| 国产小伙和50岁熟女59P| 男阳茎进女阳道啪啪| 玩小雪跪趴把腿分到最大影视频| 影音先锋女人AV女色资源| 丰满的熟妇人妻中文字幕久久| 精品人妻一区二区三区免费| 全免费A敌肛交毛片免费| 亚洲AV无码XXX麻豆艾秋| 99视频69E精品视频| 国产偷V国产偷V亚洲高清| 欧美丰满熟妇乱XXXXX视频 | BBW下身丰满18XXXX| 国产新婚夫妇叫床声不断| 欧美 亚洲 另类 丝袜 自拍| 亚洲AⅤ中文无码字幕色| AV天堂亚洲国产AV| 国色天香看片影院| 人人澡人人妻人人爽人人蜜桃| 亚洲欧美综合精品成人网站| 被夫上司强迫的女人在线中文 | 日本熟妇色XXXXX日本妇奷| 亚洲人成精品久久久久| 绯色av一区二区| 老司机午夜精品视频资源| 午夜亚洲AV永久无码精品| JZZIJZZIJ日本成熟少妇| 精品国产污污免费网站| 少妇被粗大的猛烈进出视频| 中国VODAFONE粗暴| 国精产品一品二品国精HTC| 日本妞vs黑人巨大XXXXX| 夜里十大禁用APP软件最新章节| 国产精品毛片无码| 人妻人人澡人人添人人爽人人玩| 亚洲一区二区三区AV无码蜜桃| 国产成人无码AV一区二区在线观 | 变态SM无码凌虐视频网站| 久久香综合精品久久伊人| 小雪被老汉各种姿势玩弄| 成人片在线观看地址KK4444| 免费人成年激情视频在线观看| 亚洲AV无码成人精品区欧洲| 俄罗斯13一14幻交| 欧美猛少妇色XXXXⅩ| 亚洲综合色区另类小说| 国产亚洲精久久久久久无码| 日韩精品人妻中文字幕有码 | 亚洲熟妇AV综合网五月| 国产无人区二卡三卡四卡不见星空 | 日本熟妇厨房XXXXX乱电影| 18禁真人床震无遮挡免费| 久久se精品一区二区| 午夜影视啪啪免费体验区入口| 成人A片产无码免费视频在线观看| 蜜桃女同一区二区免费AV哟| 亚洲色精品三区二区一区| 国产亚洲精品精品国产亚洲综合| 熟妇女领导呻吟疯狂| 北条麻妃国产九九九精品视频 | 67194熟妇人妻欧美日韩| 久久久久久久久久精品电影| 亚洲AV无码专区国产乱码APP| 国产高清中文版HD中字| 色狠狠色噜噜AV一区| 班级每人C了我半小时班长| 欧美成人V片观看| 中文字幕人成无码人妻| 久久精品无码中文字幕老司机| 亚洲成人AV网址| 国语自产偷拍精品视频| 无码专区一ⅤA亚洲V专区在线| 公和熄小婷乱中文字幕| 三人一起玩弄娇妻高潮| 插我一区二区在线观看| 人妻少妇一区二区| ぱらだいす天堂中文WWW| 欧美精品黑人成人另类视频| ◇一本大道香蕉中文在线| 蜜桃AV蜜臀AV色欲AV麻| 荫道BBWBBB高潮潮喷| 久久天天躁狠狠躁夜夜免费观看 | 免费无码专区毛片高潮喷水| 伊伊人成亚洲综合人网香| 久久精品人人做人人爽电影 | 久久久久亚洲AV无码专区喷水| 亚洲色婷婷综合开心网| 精品无码人妻夜人多侵犯18| 亚洲色偷偷偷综合网| 久久久99精品成人片中文字幕| 亚洲香蕉中文日韩V日本| 久久精品麻豆日日躁夜夜躁| 亚洲制服丝袜AV一区二区三区| 久久久精品中文字幕麻豆发布 | 两毫米的小洞你却稳稳命中| 曰本女人与公拘交酡| 免费无码又爽又刺激高潮的APP| 装醉把自己给流浪汉玩| 欧美成人精品在线| Xx性欧美肥妇精品久久久久久久久| 强奷漂亮雪白丰满少妇| 波多野结衣乳巨码无在线| 日韩VS欧美VS亚洲VS无码| 丰满少妇人妻HD高清大乳| 无码国产精品一区二区免费模式 | 女人扒开腿让男人狂桶30分钟| AV大片在线无码免费| 人人添人人妻人人爽夜欢视AV| 丁香五月婷激情综合第九色| 我和公GONG在厨房日本电影| 国产小视频A在线观看| 亚洲色成人网站WWW永久男男| 久久男人AV资源网站无码| √天堂网WWW最新版| 岳潮湿的大肥梅开二度第三部最新 | 国产成人综合久久精品推最新 | 国产在线乱子伦一区二区 | 久久久久精品国产99久久综合| 18禁H漫免费漫画无码网站国产| 青青草无码精品伊人久久蜜臀 | 挺进绝色校花的紧窄小肉| 国产亚洲色婷婷久久99精品| 亚洲一区二区三区成人片在线观看| 蜜国产精品JK白丝AV网站| 八戒成年私人影院| 婷婷综合另类小说色区| 精品久久久久久久久午夜福利| 在线观看成人片韩剧| 人妻无码ΑV中文字幕琪琪布 | 亚洲国产另类久久久精品小说| 久久人人爽爽人人爽人人片AV| GAY欧美猛男巨大FUCKIN| 四川少妇XXXX内谢欧美| 红桃视频成人传媒| 综合色天天鬼久久鬼色| 日产精品卡2卡三卡四卡公司| 国产日韩AⅤ无码一区二区三区| 野花社区高清在线观看视频| 人妻少妇精品专区性色AV| 国产乱子伦精品免费无码专区| 野花视频在线观看免费高清版| 人妻去按摩店被黑人按中出| 国产日产欧产美韩系列麻豆| 在厨房乱子伦对白| 日日AV拍夜夜添久久免费| 极品人妻系列少妇系列| AV天堂永久资源网AV天堂| 我国产码在线观看AV哈哈哈网站| 久久久久久精品免费免费SSS| 把女的下面扒开添视频| 亚洲AV无码蜜臀久久寂寞少妇| 男生晚上睡不着想看B站| 国产激情久久久久影院老熟女| 亚洲中文字幕日产乱码小说 | 出租屋勾搭老熟妇啪啪| 亚洲成无码电影在线观看| 欧美劲爆精品白浆视频网站| 国产人澡人澡澡澡人碰视频| 13277大但人文艺术日本活动| 天天在线看无码AV片| 久热中文字幕无码视频| 高H禁伦餐桌上的肉伦| 一本大道东京热无码| 天堂在\/线中文在线8| 美女张开双腿久久久久久|