您好,登錄后才能下訂單哦!
今天小編給大家分享一下怎么用VuePress開發一個代碼復制插件的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
但是如果你在配置文件中要做的事情太多了,最好還是將它們提取到單獨的插件中,然后通過設置絕對路徑或者通過 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
,可以在運行過程中看到我們的插件名字和打印結果:
現在我們可以設想下我們的代碼復制插件的效果了,我想要實現的效果是:
在代碼塊的右下角有一個 Copy 文字按鈕,點擊后文字變為 Copied!然后一秒后文字重新變為 Copy,而代碼塊里的代碼則在點擊的時候復制到剪切板中。
如果是在 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) } }
刷新下瀏覽器里的頁面,然后查看打印:
接下來就要思考如何寫入按鈕元素了。
當然我們可以使用原生 JavaScript 一點點的創建元素,然后插入其中,但我們其實是在一個支持 Vue 語法的項目里,其實我們完全可以創建一個 Vue 組件,然后將組件的實例掛載到元素上。那用什么方法掛載呢?
我們可以在 Vue 的全局 API 里,找到 Vue.extend
API,看一下使用示例:
// 要掛載的元素 <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開發一個代碼復制插件”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。