欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue組件文檔生成工具庫的方法

 更新時(shí)間:2021年08月10日 16:42:58   作者:白云蒼狗  
本文主要介紹了Vue組件文檔生成工具庫的方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

程序員最討厭的兩件事情,第一種是寫文檔,另一種是別人沒有寫文檔。有沒有直接根據(jù)vue組件生成文檔的呢?當(dāng)然是有的的。但第三方使用起來不一定能和現(xiàn)有項(xiàng)目結(jié)合使用,往往需要額外的注釋用來標(biāo)記提取信息。使用第三方的一些比較常見問題

  • 文檔提取信息不全面,可能有些信息你需要提取但是它又不支持。這種情況下就只能修改三方的插件源碼了。
  • 需要額為的注釋信息來標(biāo)記,例如 vuese 需要給方法 打 @vuese、@arg 等標(biāo)記來提供方法信息。

俗話說自己動(dòng)手豐衣足食,打造自己的vue文檔生成工具與自己項(xiàng)目結(jié)合使用。一個(gè)組件文檔大致需要提供 組件名稱和描述(name)、組件屬性(props)、組件方法(methods)、組件事件(event)、插槽(slot) 這幾個(gè)部分,以及還需要這個(gè)幾個(gè)部分的注釋組成生成描述信息。接下來一步步實(shí)現(xiàn)對(duì)著幾個(gè)部分的提取實(shí)現(xiàn)。

解析.vue 文件

一般一個(gè).vue文件分三個(gè)部分 template、script、style、style部分的內(nèi)容我們不需要,我們需要分別提取出 template 和 script 內(nèi)容。Vue官方開發(fā)了 Vue-template-compiler 庫專門用于Vue解析,我們可以直接使用它來解析提取.vue文件, Vue-template-compiler 提供了一個(gè) parseComponent 方法可以對(duì)原始的Vue文件進(jìn)行處理。

const compiler = require('vue-template-compiler')
const result = compiler.parseComponent(vueStr, [options])

// parseComponent 返回  template、script、style內(nèi)容,
export interface SFCDescriptor {
  template: SFCBlock | undefined;
  script: SFCBlock | undefined;
  styles: SFCBlock[];
  customBlocks: SFCBlock[];
}

拿到各個(gè)部分文本后,還需要將它轉(zhuǎn)成ast(抽象語法樹),template 部分內(nèi)容可以直接使用 Vue-template-compiler 提供的 compile 方法直接生成ast, script部分需要借助其他的生成ast了,這里使用 babel 的模塊來處理 js 文本。

const compiler = require('vue-template-compiler')
//vueStr .vue 文件內(nèi)容
const vue = compiler.parseComponent(vueStr)

//生成html部分的 ast 
let template = compiler.compile(vue.template.content, {
    preserveWhitespace: false,
    comments: true // 生成注釋信息
})

使用 @babel/parser(Babel解析器,是Babel中使用的JavaScript解析器)來處理js 文本內(nèi)容。

const parse = require('@babel/parser');

//生成js部分的 ast
let jsAst = parse.parse(vue.script.content, {
    allowImportExportEverywhere: true 
})

提取文檔信息

通過上一步的文件解析工作,我們成功獲取到了Vue的模板ast和script中的js的ast,下一步我們就可以從中獲取我們想要的信息了。這里需要使用到 @babel/traverse 這個(gè)工具,用來遍歷 js ast 的節(jié)點(diǎn)工具。可以在這里查看 ast 的生成內(nèi)容,方便查看各種節(jié)點(diǎn)信息。

const traverse = require('@babel/traverse');
traverse.default(jsAst, {
  enter(path){ // 開始

  },
  // 支持自定義節(jié)點(diǎn) 比如當(dāng)節(jié)點(diǎn)類型 為 ExportDefaultDeclaration 時(shí)掉這個(gè)方法
  ExportDefaultDeclaration(){

  }
})

提取組件名稱、描述、props、methods、model

export default 生成的對(duì)應(yīng)節(jié)點(diǎn)類型是 ExportDefaultDeclaration,declaration 屬性就是對(duì)應(yīng)的組件的 options 了,遍歷 declaration 的屬性可以獲取到 name、props、methods、model 等節(jié)點(diǎn)信息。

示例

let componentInfo = {}
traverse.default(jsAst, {
  ExportDefaultDeclaration(path){
    path.node.declaration.properties.forEach(item => {
        switch (item.key.name) {
            case 'props':
                componentInfo.props = extractProps(item) // 提取 props
                break;
            case 'methods':
                componentInfo.methods = extractMethods(item)  // 提取 methods
                break
            case 'name':
                componentInfo.name = item.value.value // 獲取組件名稱
                break
            case 'model':
                componentInfo.model = extractModel(item)  // 提取 model
                break
            default:
                break;
        }
    });
  }
})

提取描述

js中注釋分為單行和多行兩種,生成ast也會(huì)生成不同類型的,可以看下面例子。

/** 
 * 多行備注
 * 用來上傳文檔信息
 */
// 單行備注
export default {
}
// 結(jié)尾注釋

可以看到會(huì) CommentBlock、 CommentLine 兩種類型的節(jié)點(diǎn),還有頭部的會(huì)放在 leadingComments 里,底部的注釋在 trailingComments 里。


一般會(huì)把組件描述注釋放在 export default 上面,簡(jiǎn)單提取注釋信息

// ExportDefaultDeclaration 插入如下代碼 
if (path.node.leadingComments) {
    componentInfo.desc = path.node.leadingComments.map(item => {
        if (item.type === 'CommentLine') {
            return item.value.trim()
        } else {
            return item.value.split('\n').map(item => item.replace(/[\s\*]/g, '')).filter(Boolean)
        }
    }).toString()
}

提取 methods

因?yàn)?methods 中的注釋需要額外描述 出參、入?yún)⒌刃畔⑿枰~外處理,jsdoc注釋規(guī)范使用還是比較大眾的,這里根據(jù)需要自己定義提取規(guī)則,還需要提取 async 用來標(biāo)識(shí)是否是異步函數(shù)。

/**
 * 方法描述
 * @param {Bool} type 參數(shù)描述
 * @returns 返回值描述
 */

提取 props

props 的提取需要區(qū)分下面幾種情況,default 和 validator 還是提取還是有點(diǎn)麻煩的,validator 校驗(yàn)還可以通過注釋簡(jiǎn)單描述來提取,但是 default 就不好處理了。

{
    propA: Number, // 只有類型
    propB: [String, Number], // 只有類型但是支持多種
    propC: { 
      type: String,
      required: true
    },
    propD: {
      type: Number,
      default: 100 // 帶有默認(rèn)值 
    },
    propE: {
      type: Object,
      default () { // 默認(rèn)值 需要函數(shù)返回
        return { message: 'hello' }
      }
    },
    propF: {
      default: function () { // 默認(rèn)值 需要函數(shù)返回 和上面的 default 的 ast 節(jié)點(diǎn)類型是不同的
        return { message: 'hello' }
      }
      validator: function (value) { // 校驗(yàn)
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
}

我這里對(duì) default 處理是借助 @babel/generator 將 default 轉(zhuǎn)換代碼, 通過eval轉(zhuǎn)成函數(shù)調(diào)用返回會(huì)默認(rèn)值。types 是 @babel/types 模塊,用來判斷節(jié)點(diǎn)類型的。

// 獲取Props默認(rèn)值
function getDefaultVal (node) {
    if (types.isRegExpLiteral(node) || types.isBooleanLiteral(node) || types.isNumericLiteral(node) || types.isStringLiteral(node)) {
        return node.value
    } else if (types.isFunctionExpression(node) || types.isArrowFunctionExpression(node) || types.isObjectMethod(node)) {
        try {
            let code = generate.default(types.isObjectMethod(node) ? node.body : node).code
            let fun = eval(**0,${types.isObjectMethod(node) ? 'function ()' : ''} $[code]**)
            return JSON.stringify(fun())
        } catch (error) {
        }
    }
}

提取 model

這個(gè)比較簡(jiǎn)單,直接獲取就可以了。

提取組件Events

組件的事件沒法直接獲取到對(duì)應(yīng)節(jié)點(diǎn),只能通過 $emit 方法來定位事件位置,在 traverse 中可以使用 MemberExpress(復(fù)雜類型節(jié)點(diǎn)),然后通過節(jié)點(diǎn)上的屬性名是否是 $emit 判斷是否是事件。

可以看到事件名稱在 MemberExpress 父級(jí)上的 arguments 里,而備注則在更上一層的里。

const extractEvents = (path) => {
    // 第一個(gè)元素是事件名稱
    const eventName = path.parent.arguments[0]; 
    let comments = path.parentPath.parent.leadingComments
    return {
        name: eventName.value,
        desc: comments ? comments.map(item => item.value.trim()).toString() : '——'
    }
}

MemberExpression (path) {
    // 判斷是不是event
    if (path.node.property.name === '$emit') {
        let event = extractEvents(path)
        !componentInfo.events && (componentInfo.events = {});
        if (componentInfo.events[event.name]) {
            componentInfo.events[event.name].desc = event.desc ? event.desc : componentInfo.events[event.name].desc
        } else {
            componentInfo.events[event.name] = event
        }
    }
}

在成功獲取到Events后,那么結(jié)合Events、Props、Model,就可以進(jìn)一步的判斷屬性是否支持 .sync 和 v-model。

提取組件Slots

首先需要寫一個(gè)對(duì)Vue模板的ast遍歷的函數(shù),Vue-template-compiler 沒有提供類似于 @babel/traverse 用來 遍歷 ast 的。

簡(jiǎn)單實(shí)現(xiàn)個(gè)遍歷模板抽象樹函數(shù)

const traverserTemplateAst = (ast, visitor = {}) => {
    function traverseArray (array, parent) {
        array.forEach(child => {
            traverseNode(child, parent);
        });
    }

    function traverseNode (node, parent) {
        visitor.enter && visitor.enter(node, parent);
        visitor[node.tag] && visitor[node.tag](node, parent);
        node.children && traverseArray(node.children, node);
        visitor.exit && visitor.exit(node, parent);
    }

    traverseNode(ast, null);
}

Vue模板的ast的結(jié)構(gòu)還是比較清晰的,沒有js ast 那么多的類型,只需要區(qū)分不同tag就可以了。注釋會(huì)單獨(dú)一個(gè)節(jié)點(diǎn),所以在查找 slot 節(jié)點(diǎn)時(shí)候,還需要去找它上一個(gè)相鄰節(jié)點(diǎn),判斷是否是注釋。

traverserTemplateAst(template.ast, {
    slot (node, parent) {
        !componentInfo.slots && (componentInfo.slots = {})
        // 獲取節(jié)點(diǎn)位置
        let index = parent.children.findIndex(item => item === node)
        let desc = '無描述', name = '-';
        if (index > 0) {
            let tag = parent.children[index - 1]
            // isComment 判斷是否是 注釋
            if (tag.isComment) {
                desc = tag.text.trim()
            }
        }
        if (node.slotName) name = node.attrsMap.name
        componentInfo.slots[name] = {
            name,
            desc
        }
    }
})

結(jié)語

到這里簡(jiǎn)單的實(shí)現(xiàn)了自動(dòng)化生成vue組件信息了,當(dāng)然還有幾種情況還沒有考慮進(jìn)去,例如事件$emit 在 template 中,slot 在 render 函數(shù)中時(shí)候的情,不過提取這部分實(shí)現(xiàn)也是大同小異的了。可以在這里查看 本文源碼。

到此這篇關(guān)于Vue組件文檔生成工具庫的方法的文章就介紹到這了,更多相關(guān)Vue組件文檔生成工具內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue+ts實(shí)現(xiàn)元素鼠標(biāo)拖動(dòng)效果

    vue+ts實(shí)現(xiàn)元素鼠標(biāo)拖動(dòng)效果

    這篇文章主要為大家詳細(xì)介紹了vue+ts實(shí)現(xiàn)元素鼠標(biāo)拖動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • vue easytable組件使用詳解

    vue easytable組件使用詳解

    Vue Easytable是一個(gè)基于Vue.js的數(shù)據(jù)表格組件庫,它提供豐富的功能和靈活的配置,幫助開發(fā)者快速搭建復(fù)雜的數(shù)據(jù)表格界面,這篇文章主要介紹了vue easytable組件使用,需要的朋友可以參考下
    2023-09-09
  • vue-cli3 熱更新配置操作

    vue-cli3 熱更新配置操作

    這篇文章主要介紹了vue-cli3 熱更新配置操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • vue實(shí)現(xiàn)自定義組件掛載原型上

    vue實(shí)現(xiàn)自定義組件掛載原型上

    這篇文章主要介紹了vue實(shí)現(xiàn)自定義組件掛載原型上方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • 如何在Vue項(xiàng)目中使用axios請(qǐng)求

    如何在Vue項(xiàng)目中使用axios請(qǐng)求

    這篇文章主要介紹了如何在Vue項(xiàng)目中使用axios請(qǐng)求,對(duì)Vue感興趣的同學(xué),可以參考下
    2021-05-05
  • Vue基礎(chǔ)學(xué)習(xí)之項(xiàng)目整合及優(yōu)化

    Vue基礎(chǔ)學(xué)習(xí)之項(xiàng)目整合及優(yōu)化

    這篇文章主要給大家介紹了關(guān)于Vue基礎(chǔ)學(xué)習(xí)之項(xiàng)目整合及優(yōu)化的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Vue具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • vue使用拖拽方式創(chuàng)建結(jié)構(gòu)樹

    vue使用拖拽方式創(chuàng)建結(jié)構(gòu)樹

    這篇文章主要為大家詳細(xì)介紹了vue使用拖拽方式創(chuàng)建結(jié)構(gòu)樹,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • vue返回上一頁面時(shí)回到原先滾動(dòng)的位置的方法

    vue返回上一頁面時(shí)回到原先滾動(dòng)的位置的方法

    這篇文章主要介紹了vue返回上一頁面時(shí)回到原先滾動(dòng)的位置的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-12-12
  • vue項(xiàng)目中常見問題及解決方案(推薦)

    vue項(xiàng)目中常見問題及解決方案(推薦)

    這篇文章主要介紹了vue項(xiàng)目中常見問題及解決方案,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-10-10
  • vuex中store存儲(chǔ)store.commit和store.dispatch的用法

    vuex中store存儲(chǔ)store.commit和store.dispatch的用法

    這篇文章主要介紹了vuex中store存儲(chǔ)store.commit和store.dispatch的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-07-07

最新評(píng)論