亚洲最大看欧美片,亚洲图揄拍自拍另类图片,欧美精品v国产精品v呦,日本在线精品视频免费

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

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

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

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

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

    本地開發(fā)

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

    推薦你直接將 配置文件 作為插件使用,因?yàn)閹缀跛械牟寮?API 都可以在配置文件中使用,這在絕大多數(shù)場景下都更為方便。

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

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

    那就讓我們開始吧!

    初始化項(xiàng)目

    我們在 .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

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

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

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

    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é)果:

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

    插件設(shè)計(jì)

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

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

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

    插件開發(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)     } }

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

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

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

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

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

    // 要掛載的元素 <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í)將代碼寫入剪切版的效果,整體代碼比較簡單,就不多敘述了。

    我們修改一下 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)元素,但是這里我們需要添加到元素中,所以我們在執(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ù)制的功能。

    插件選項(xiàng)

    有的時(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')     }  }

    我們在 config.js先寫入需要用到的選項(xiàng):

    module.exports = {     plugins: [       [         require('./vuepress-plugin-code-copy'),         {           'copybuttonText': '復(fù)制',           'copiedButtonText': '已復(fù)制!'         }       ]     ] }

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

    我們再翻下 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實(shí)戰(zhàn)】手把手帶你開發(fā)一個(gè)代碼復(fù)制插件

    代碼參考

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

    贊(0)
    分享到: 更多 (0)
    網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號