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

站長資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

【VuePress實戰(zhàn)】手把手帶你開發(fā)一個代碼復制插件

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

【VuePress實戰(zhàn)】手把手帶你開發(fā)一個代碼復制插件

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

本地開發(fā)

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

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

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

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

那就讓我們開始吧!

初始化項目

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

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

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

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

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

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

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

【VuePress實戰(zhàn)】手把手帶你開發(fā)一個代碼復制插件

插件設計

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

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

【VuePress實戰(zhàn)】手把手帶你開發(fā)一個代碼復制插件

插件開發(fā)

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

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

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

看下示例代碼:

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

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

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)     } }

刷新下瀏覽器里的頁面,然后查看打?。?/p>

【VuePress實戰(zhàn)】手把手帶你開發(fā)一個代碼復制插件

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

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

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

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

結果如下:

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

那接下來,我們就創(chuàng)建一個 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>

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

我們修改一下 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 獲取要復制的代碼內(nèi)容,然后寫入到實例的 code 屬性,在組件中,我們是通過 this.code獲取的。

第二是我們沒有使用 $mount(element),直接傳入一個要掛載的節(jié)點元素,這是因為 $mount() 的掛載會清空目標元素,但是這里我們需要添加到元素中,所以我們在執(zhí)行 instance.$mount()后,通過 instance.$el獲取了實例元素,然后再將其 appendChild 到每個代碼塊中。關于 $el的使用可以參考官方文檔的 el 章節(jié) 。

此時,我們的文件目錄如下:

.vuepress ├─ vuepress-plugin-code-copy  │  ├─ CodeCopy.vue │  ├─ clientRootMixin.js │  ├─ index.js │  └─ package.json └─ config.js

至此,其實我們就已經(jīng)實現(xiàn)了代碼復制的功能。

插件選項

有的時候,為了增加插件的可拓展性,會允許配置可選項,就比如我們不希望按鈕的文字是 Copy,而是中文的「復制」,復制完后,文字變?yōu)?「已復制!」,該如何實現(xiàn)呢?

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

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參數(shù)可以接收到我們在 config.js 寫入的選項,但我們怎么把這些參數(shù)傳入 CodeCopy.vue 文件呢?

我們再翻下 VuePress 提供的 Option API,可以發(fā)現(xiàn)有一個 define API,其實這個 define 屬性就是定義我們插件內(nèi)部使用的全局變量。我們修改下 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')     }  }

現(xiàn)在我們已經(jīng)寫入了兩個全局變量,組件里怎么使用呢?答案是直接使用!

我們修改下 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實戰(zhàn)】手把手帶你開發(fā)一個代碼復制插件

代碼參考

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

贊(0)
分享到: 更多 (0)
?
網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號
らだ天堂中文在线| 国产乱子伦视频在线播放| 色窝窝无码一区二区三区色欲| 国产成A人片在线观看视频| 亚洲国产欧美在线观看片不卡| 久久久久亚洲AV无码专| 亚洲色成人网站www观看入口| 看全色黄大色黄女片爽在线看| 18禁裸男晨勃露J毛免费观看| 少妇无码AV无码一区| 好嗨哟片在线观看| 好男人好资源电影在线播放| となりの家のネツト在线| 午夜无码伦费影视在线观看| 和朋友换娶妻野外夫妇3| 中文字幕免费不卡二区| 欧美成人精品视频在线观看| 又粗又大又硬毛片免费看| 日韩人妻AV在线| 久久久久久久精品无码Av少妇| 成人毛片无码一区二区| 久久99国产综合精品| 99成人国产综合久久精品| 18禁免费无码无遮挡不卡网站| 亚洲中文字幕无码久久2020| 亚洲色无码中文字幕手机在线| 亚洲日韩丝袜熟女变态夜夜爽| 亚洲MV砖码砖区2021在线| 无码人妻一区二区三区免费手机| 人妻激情偷乱一区二区三区AV | 爸的比老公大两倍儿媳叫什么呢| 亚洲 春色 另类 小说| 日本经典片免费看| 老熟妇高潮一区二区三区| 俄罗斯18XXOO在线| 亚洲国产精久久久久久久| 日本极品少妇VIDEOSSEX| 免费人妻精品一区二区三区| 孩交乱子XXXX高清影视| 亚洲AV无码一区二区高潮| 天天躁日日躁狠狠躁2018| 欧美成人精品视频在线不卡 | Y1111111少妇影院无码| 欧美人成人精品视频在线观看| 国精产品一区一区三区糖心| 粗大的内捧猛烈进出动态图| A级毛片毛片免费观看久潮喷| 永久免费AⅤ无码网站国产| 日日碰日日摸夜夜爽无码| 久久久久久久久精品成人| 俄罗斯卖CSGO的网站| 中文字幕AV无码免费久久| 亚洲乱色熟女一区二区三区麻豆| 无码αv人妻一区二区三区| 日本乱人伦AⅤ精品潮喷| 色婷婷亚洲十月十月色天| 午夜精品久久久久久久99热| 亚洲国产不卡久久久久久| 无码人妻丰满熟妇啪啪7774| 男人激烈吮乳吃奶动态图| 日本强伦姧人妻69影院| 五十路丰满中年熟女中出| 亚洲AⅤ永久无码精品三区在线| 太深太粗太大太猛太爽了视频| 亚洲AV色香蕉一区二区三区夜夜嗨 | 嫩模超大胆大尺度人体写真| 久久中文字幕无码一区二区| 久久久久久久精品成人热色戒 | 久久毛片免费看一区二区三区| 成人免费毛片内射美女APP| 成人影院YY111111在线| 波多野42部无码喷潮| 好爽…又高潮了毛片喷水| 国产在线无码免费网站永久| 老骚B老太太视频| 嫩草欧美曰韩国产大片| 啪啪啪1000免费观看| 无码AV波多野结衣久久| 18无码粉嫩小泬无套在线观看| 欧美精品亚洲日韩AⅤ| 欧美一区二区三区激情| 日韩少妇内射免费播放| 小浪蹄子蜜水噗呲噗呲的| 亚洲孕妇精品无码av| 99精品国产一区二区电影| 97丨九色丨国产人妻▌| 波多野结衣亚洲AV手机在线| 国产AV永久无码精品网站| 国产精品久久久久久麻豆一区| 国产精华AV午夜在线观看| 久久精品人人看人人爽| 国产AⅤ激情无码久久久无码| 激情伊人五月天久久综合| 免费午夜无码18禁无码影视| 亚洲AV日韩综合一区| 亚洲精品AⅤ中文字幕乱码| 丰满少妇弄高潮了WWW| 精品无码一区二区三区| 天堂А√在线最新版在线8| 一面亲上边一面膜下边的免费 | 高h乱好爽要尿了潮喷了| 国产区精品一区二区不卡中文| 狼人在线二线三线区别大吗| 色翁荡息又大又硬又粗视频| 337P日本欧洲亚洲大胆在线| 拔萝卜全程不该盖被子怎么办 | 国产真人无码作爱免费视频APP| 久久WWW免费人成_看片| 日韩AV无码精品人妻系列| 亚洲国产一区二区三区波多野结衣| JIJZZIZZ老师出水喷水多| 丰满人妻熟妇乱又伦精品APP| 国产综合久久久久| 欧美 日韩 高清 国产AⅤ一区| 人人妻人人澡人人爽欧美精品| 色综合久久一区二区三区| 无码AV蜜臀AⅤ色欲在线观看| 中文字幕乱码人妻综合二区三区 | 亚洲欧洲日产国码AⅤ| 成 人免费 在线手机版视| 麻花传媒免费网站在线观看| 亚洲国产成人精品无码区2021 | 99国产精品自在自在久久| 无码AV免费精品一区二区三区| 中文字幕久精品免费视频| 妓女院18禁止观看| 欧美性狂猛XXXXX深喉| 欧美老少配XXXOOO性HD| 亚洲 自拍 另类 欧美 综合| 99久久精品费精品国产| 精品亚洲国产成人AV不卡| 午夜三级A三级三点窝| 超碰97人人做人人爱综合| 92久久偷偷做嫩草影院免费看| 天天躁日日躁很很躁2022| 顶级私人家庭影院| 人妻丰满熟妇AV无码区APP| www.性xxxxx| 色天使色偷偷色噜噜噜| 97久久精品无码一区二区| 免费乱理伦片在线观看八戒| A级毛片毛片免费观看丝瓜| 欧美日韩一区二区三区人妻| 午夜香吻高清观看视频在线| 吃瓜曝光黑料155FUN| 久久久亚洲熟妇熟女中文字幕| 亚洲AV无码久久寂寞少妇| ZOOM与人性ZOOM| 老司机带带我免费看| 孕妇奶水仑乱A级毛片免费看| 久久久久无码精品国产AV蜜桃1| 亚洲欧美精品午睡沙发| 国产精品无码免费播放| 婷婷丁香六月激情综合啪 | 两个奶头被吃到高潮什么感觉| 熟妇人妻AV无码一区二区三区| 再灬再灬再灬深一点舒服| 国产精品美女久久久浪潮AV| 人妻被黑人与白人巨大中出| 中国农村熟妇性视频| 国产精品岛国久久久久| 少妇伦子伦精品无码STYLES| 办公室的交易HD在线观看| 人妻精品AAAA中文字幕69| 久久久精品成人免费观看国产| 天天做天天爱夜夜爽毛片| 久久国产午夜精品理论片| JEALOUSVUE成熟五十| 熟妇人妻av无码一区二区三区 | 久久久久夜色精品国产| 伊人色综合视频一区二区三区| 久久久午夜成人噜噜噜| 亚洲欧美综合精品AⅤ一区二区 | 亚洲AV永久无码精品桃花岛知道| 国产精品无码V在线观看| 亚洲AV无码专区国产乱码波多野| 九热爱视频精品视频| 又粗又大内射免费视频小说| 久久亚洲中文字幕无码| 在公交上被灌满白浆的视频| 久久五月丁香合缴情网| 午夜精品射精入后重之免费观看 | AV成人无码无在线观看| 俄罗斯女人与马Z00Z视频| 天天澡天天添天天摸97影院| 娇喘潮喷抽搐高潮在线观看视频| 99久RE热视频这只有精品6| 男女嘿咻发声动态图| 99热精品国产三级在线| 久久久久99精品成人片试看| 最新国产精品拍自在线播放| 亚洲Av无码成人黄网站在线| 日韩少妇人妻夜夜爽| 久久国产欧美日韩精品| 国产精品自产拍在线观看| ぱらだいす天堂中文WWW| 伊人久久大香线蕉AV波多野结衣 | けんじゃたいむMANA原神| 亚洲成人综合av| 九九国产精品无码免费视频|