您好,登錄后才能下訂單哦!
今天小編給大家分享一下怎么用VuePress開發(fā)一個(gè)代碼復(fù)制插件的相關(guān)知識(shí)點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識(shí),所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
但是如果你在配置文件中要做的事情太多了,最好還是將它們提取到單獨(dú)的插件中,然后通過設(shè)置絕對(duì)路徑或者通過 require 來使用它們:
module.exports = { plugins: [ path.resolve(__dirname, './path/to/your-plugin.js'), require('./another-plugin'), ], }
那就讓我們開始吧!
我們?cè)?.vuepress
文件夾下新建一個(gè) vuepress-plugin-code-copy
的文件夾,用于存放插件相關(guān)的代碼,然后命令行進(jìn)入到該文件夾,執(zhí)行 npm init
,創(chuàng)建 package.json
,此時(shí)文件的目錄為:
.vuepress ├─ vuepress-plugin-code-copy │ └─ package.json └─ config.js
我們?cè)?vuepress-plugin-code-copy
下新建一個(gè) index.js
文件,參照官方文檔插件示例中的寫法,我們使用返回對(duì)象的函數(shù)形式,這個(gè)函數(shù)接受插件的配置選項(xiàng)作為第一個(gè)參數(shù)、包含編譯期上下文的 ctx 對(duì)象作為第二個(gè)參數(shù):
module.exports = (options, ctx) => { return { // ... } }
再參照官方文檔 Option API 中的 name,以及生命周期函數(shù)中的 ready 鉤子,我們寫一個(gè)初始的測(cè)試代碼:
module.exports = (options, ctx) => { return { name: 'vuepress-plugin-code-copy', async ready() { console.log('Hello World!'); } } }
此時(shí)我們運(yùn)行下 yarn run docs:dev
,可以在運(yùn)行過程中看到我們的插件名字和打印結(jié)果:
現(xiàn)在我們可以設(shè)想下我們的代碼復(fù)制插件的效果了,我想要實(shí)現(xiàn)的效果是:
在代碼塊的右下角有一個(gè) Copy 文字按鈕,點(diǎn)擊后文字變?yōu)?Copied!然后一秒后文字重新變?yōu)?Copy,而代碼塊里的代碼則在點(diǎn)擊的時(shí)候復(fù)制到剪切板中。
如果是在 Vue 組件中,我們很容易實(shí)現(xiàn)這個(gè)效果,在根組件 mounted
或者 updated
的時(shí)候,使用 document.querySelector
獲取所有的代碼塊,插入一個(gè)按鈕元素,再在按鈕元素上綁定點(diǎn)擊事件,當(dāng)觸發(fā)點(diǎn)擊事件的時(shí)候,代碼復(fù)制到剪切板,然后修改文字,1s 后再修改下文字。
那 VuePress 插件有方法可以控制根組件的生命周期嗎?我們查閱下 VuePress 官方文檔的 Option API,可以發(fā)現(xiàn) VuePress 提供了一個(gè) clientRootMixin 方法:
指向 mixin 文件的路徑,它讓你可以控制根組件的生命周期
看下示例代碼:
// 插件的入口 const path = require('path') module.exports = { clientRootMixin: path.resolve(__dirname, 'mixin.js') }
// mixin.js export default { created () {}, mounted () {} }
這不就是我們需要的嗎?那我們動(dòng)手吧,修改 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
下新建一個(gè) clientRootMixin.js
文件,代碼寫入:
export default { updated() { setTimeout(() => { document.querySelectorAll('div[class*="language-"] pre').forEach(el => { console.log('one code block') }) }, 100) } }
刷新下瀏覽器里的頁面,然后查看打印:
接下來就要思考如何寫入按鈕元素了。
當(dāng)然我們可以使用原生 JavaScript 一點(diǎn)點(diǎn)的創(chuàng)建元素,然后插入其中,但我們其實(shí)是在一個(gè)支持 Vue 語法的項(xiàng)目里,其實(shí)我們完全可以創(chuàng)建一個(gè) Vue 組件,然后將組件的實(shí)例掛載到元素上。那用什么方法掛載呢?
我們可以在 Vue 的全局 API 里,找到 Vue.extend
API,看一下使用示例:
// 要掛載的元素 <div id="mount-point"></div>
// 創(chuàng)建構(gòu)造器 var Profile = Vue.extend({ template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>', data: function () { return { firstName: 'Walter', lastName: 'White', alias: 'Heisenberg' } } }) // 創(chuàng)建 Profile 實(shí)例,并掛載到一個(gè)元素上。 new Profile().$mount('#mount-point')
結(jié)果如下:
// 結(jié)果為: <p>Walter White aka Heisenberg</p>
那接下來,我們就創(chuàng)建一個(gè) Vue 組件,然后通過 Vue.extend
方法,掛載到每個(gè)代碼塊元素中。
在 vuepress-plugin-code-copy
下新建一個(gè) 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>
該組件實(shí)現(xiàn)了按鈕的樣式和點(diǎn)擊時(shí)將代碼寫入剪切版的效果,整體代碼比較簡(jiǎn)單,就不多敘述了。
我們修改一下 clientRootMixin.js
:
import CodeCopy from './CodeCopy.vue' import Vue from 'vue' export default { updated() { // 防止阻塞 setTimeout(() => { document.querySelectorAll('div[class*="language-"] pre').forEach(el => { // 防止重復(fù)寫入 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) } }
這里注意兩點(diǎn),第一是我們通過 el.innerText
獲取要復(fù)制的代碼內(nèi)容,然后寫入到實(shí)例的 code
屬性,在組件中,我們是通過 this.code
獲取的。
第二是我們沒有使用 $mount(element)
,直接傳入一個(gè)要掛載的節(jié)點(diǎn)元素,這是因?yàn)?$mount()
的掛載會(huì)清空目標(biāo)元素,但是這里我們需要添加到元素中,所以我們?cè)趫?zhí)行 instance.$mount()
后,通過 instance.$el
獲取了實(shí)例元素,然后再將其 appendChild
到每個(gè)代碼塊中。關(guān)于 $el
的使用可以參考官方文檔的 el 章節(jié) 。
此時(shí),我們的文件目錄如下:
.vuepress ├─ vuepress-plugin-code-copy │ ├─ CodeCopy.vue │ ├─ clientRootMixin.js │ ├─ index.js │ └─ package.json └─ config.js
至此,其實(shí)我們就已經(jīng)實(shí)現(xiàn)了代碼復(fù)制的功能。
有的時(shí)候,為了增加插件的可拓展性,會(huì)允許配置可選項(xiàng),就比如我們不希望按鈕的文字是 Copy,而是中文的「復(fù)制」,復(fù)制完后,文字變?yōu)?「已復(fù)制!」,該如何實(shí)現(xiàn)呢?
前面講到,我們的 index.js
導(dǎo)出的函數(shù),第一個(gè)參數(shù)就是 options 參數(shù):
const path = require('path'); module.exports = (options, ctx) => { return { name: 'vuepress-plugin-code-copy', clientRootMixin: path.resolve(__dirname, 'clientRootMixin.js') } }
我們?cè)?config.js
先寫入需要用到的選項(xiàng):
module.exports = { plugins: [ [ require('./vuepress-plugin-code-copy'), { 'copybuttonText': '復(fù)制', 'copiedButtonText': '已復(fù)制!' } ] ] }
我們 index.js
中通過 options
參數(shù)可以接收到我們?cè)?config.js
寫入的選項(xiàng),但我們?cè)趺窗堰@些參數(shù)傳入 CodeCopy.vue
文件呢?
我們?cè)俜?VuePress 提供的 Option API,可以發(fā)現(xiàn)有一個(gè) define API,其實(shí)這個(gè) 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)寫入了兩個(gè)全局變量,組件里怎么使用呢?答案是直接使用!
我們修改下 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開發(fā)一個(gè)代碼復(fù)制插件”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會(huì)為大家更新不同的知識(shí),如果還想學(xué)習(xí)更多的知識(shí),請(qǐng)關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。