tdesign vue初始化組件源碼解析
前言
Tdesign-vue 是一由騰訊開源的 Vue.js 組件庫(kù)。我們知道,這些大型的組件庫(kù)業(yè)務(wù)覆蓋面很廣,基本都包含了很多組件,很多組件包含了一些通用性代碼,如果每開發(fā)一個(gè)組件,都去把這些通用性代碼復(fù)制出來(lái),無(wú)疑是非常繁瑣的,那么作者在開發(fā)這些組件時(shí)是如何做的呢?
學(xué)習(xí)目標(biāo):
- 新增組件: npm run init [組件名]
- 刪除組件:npm run init [組件名] del
資源:
源碼地址:tdesign-vue/index.js
源碼
找到用于初始化組件的源碼,如圖:

腳本的入口
function init() {
const [component, isDeleted] = process.argv.slice(2);
if (!component) {
console.error('[組件名]必填 - Please enter new component name');
process.exit(1);
}
const indexPath = path.resolve(cwdPath, 'src/index.ts');
const toBeCreatedFiles = config.getToBeCreatedFiles(component);
if (isDeleted === 'del') {
deleteComponent(toBeCreatedFiles, component);
deleteComponentFromIndex(component, indexPath);
} else {
addComponent(toBeCreatedFiles, component);
insertComponentToIndex(component, indexPath);
}
}
函數(shù)接受兩個(gè)參數(shù): Component 和 isDelete。
component參數(shù)是要?jiǎng)?chuàng)建或刪除的組件的名稱isDelete參數(shù)是一個(gè)標(biāo)志,指示是否應(yīng)該創(chuàng)建或刪除該組件。
函數(shù)首先檢查是否提供了組件參數(shù)。如果未提供,則向控制臺(tái)輸出一條錯(cuò)誤消息,函數(shù)退出。否則,函數(shù)將繼續(xù)執(zhí)行。
之后,該函數(shù)獲取需要?jiǎng)?chuàng)建或刪除的文件列表,以便添加或刪除組件。然后檢查 isDelete 參數(shù)的值,以確定是否應(yīng)該創(chuàng)建或刪除組件。如果 isDelete 等于 del,則函數(shù)調(diào)用 deleteComponent 函數(shù)來(lái)刪除組件,然后調(diào)用 deleteComponentFromIndex 函數(shù)來(lái)從項(xiàng)目的索引文件中刪除組件。如果 isDelete 不等于 del,則函數(shù)調(diào)用 addComponent 函數(shù)創(chuàng)建組件,然后調(diào)用 insertComponentToIndex 函數(shù)將組件添加到項(xiàng)目的索引文件中。
創(chuàng)建目錄
function addComponent(toBeCreatedFiles, component) {
// At first, we need to create directories for components.
Object.keys(toBeCreatedFiles).forEach((dir) => {
const _d = path.resolve(cwdPath, dir);
fs.mkdir(_d, { recursive: true }, (err) => {
if (err) {
utils.log(err, 'error');
return;
}
console.log(`${_d} directory has been created successfully!`);
// Then, we create files for components.
const contents = toBeCreatedFiles[dir];
contents.files.forEach((item) => {
if (typeof item === 'object') {
if (item.template) {
outputFileWithTemplate(item, component, contents.desc, _d);
}
} else {
const _f = path.resolve(_d, item);
createFile(_f, '', contents.desc);
}
});
});
});
}
該函數(shù)接受兩個(gè)參數(shù): toBeCreatedFiles 和 component。
toBeCreatedFiles參數(shù)是一個(gè)對(duì)象,它包含為了添加組件而需要?jiǎng)?chuàng)建的目錄和文件的列表component參數(shù)是要?jiǎng)?chuàng)建的組件的名稱。
函數(shù)首先迭代 toBeCreatedFiles 對(duì)象的鍵,這些鍵表示需要?jiǎng)?chuàng)建的目錄。對(duì)于每個(gè)目錄,該函數(shù)使用 fs.mkdir 函數(shù)創(chuàng)建目錄。如果目錄已經(jīng)存在,則函數(shù)將錯(cuò)誤消息記錄到控制臺(tái)。
創(chuàng)建目錄后,函數(shù)將遍歷需要為組件創(chuàng)建的文件列表。如果文件是包含模板屬性的對(duì)象,則函數(shù)調(diào)用 outputFileWithTemplate 函數(shù)以使用模板創(chuàng)建文件。如果文件不是具有模板屬性的對(duì)象,則函數(shù)調(diào)用 createFile 函數(shù)創(chuàng)建空文件。
內(nèi)容寫入
function insertComponentToIndex(component, indexPath) {
const upper = getFirstLetterUpper(component);
// last import line pattern
const importPattern = /import.*?;(?=\n\n)/;
// components pattern
const cmpPattern = /(?<=const components = {\n)[.|\s|\S]*?(?=};\n)/g;
const importPath = getImportStr(upper, component);
const desc = '> insert component into index.ts';
let data = fs.readFileSync(indexPath).toString();
if (data.match(new RegExp(importPath))) {
utils.log(`there is already ${component} in /src/index.ts`, 'notice');
return;
}
// insert component at last import and component lines.
data = data.replace(importPattern, (a) => `${a}\n${importPath}`).replace(cmpPattern, (a) => `${a} ${upper},\n`);
fs.writeFile(indexPath, data, (err) => {
if (err) {
utils.log(err, 'error');
} else {
utils.log(`${desc}\n${component} has been inserted into /src/index.ts`, 'success');
}
});
}
這個(gè)函數(shù)接受兩個(gè)參數(shù): component 和 indexPath。
component參數(shù)是要插入的組件的名稱indexPath參數(shù)是項(xiàng)目索引文件的路徑。
該函數(shù)首先定義兩個(gè)正則表達(dá)式: importPattern 和 cmpPattern。
importPattern正則表達(dá)式用于匹配索引文件中的最后一個(gè)import語(yǔ)句cmpPattern正則表達(dá)式用于匹配索引文件中的組件列表。
接下來(lái),函數(shù)使用 getImportStr 函數(shù),使用變量(組件名稱的大寫版本)為新組件生成導(dǎo)入語(yǔ)句。
然后,該函數(shù)使用 fs.readFileSync 函數(shù)讀取索引文件的內(nèi)容,并在文件中搜索 importPattern 和 cmpPattern 正則表達(dá)式。如果文件中已經(jīng)存在新組件的 import 語(yǔ)句,則函數(shù)將消息記錄到控制臺(tái)并返回。否則,該函數(shù)將最后一個(gè) import 語(yǔ)句替換為新 import 語(yǔ)句,并將組件列表替換為包含新組件的新組件列表。最后,函數(shù)使用 fs.writeFile 函數(shù)將修改后的索引文件內(nèi)容寫回文件。
刪除目錄
function deleteComponent(toBeCreatedFiles, component) {
const snapShotFiles = getSnapshotFiles(component);
const files = Object.assign(toBeCreatedFiles, snapShotFiles);
Object.keys(files).forEach((dir) => {
const item = files[dir];
if (item.deleteFiles && item.deleteFiles.length) {
item.deleteFiles.forEach((f) => {
fs.existsSync(f) && fs.unlinkSync(f);
});
} else {
utils.deleteFolderRecursive(dir);
}
});
utils.log('All radio files have been removed.', 'success');
}
該函數(shù)接受兩個(gè)參數(shù): toBeCreatedFiles 和 Component。
- toBeCreatedFiles 參數(shù)是一個(gè)包含與組件關(guān)聯(lián)的目錄和文件列表的對(duì)象
- component參數(shù)是要?jiǎng)h除的組件的名稱。
該函數(shù)首先調(diào)用 getSnapshoFiles 函數(shù)以獲取與組件關(guān)聯(lián)的快照文件列表。然后,它使用 Object.sign 函數(shù)將該列表與 toBeCreatedFiles 對(duì)象合并。
接下來(lái),函數(shù)迭代合并對(duì)象的鍵,這些鍵表示需要?jiǎng)h除的目錄和文件。對(duì)于每個(gè)鍵,該函數(shù)檢查是否設(shè)置了關(guān)聯(lián)值的 deleteFiles 屬性。如果是,函數(shù)將遍歷文件列表并使用 fs.unlinkSync 函數(shù)刪除它們。如果未設(shè)置 deleteFiles 屬性,該函數(shù)將調(diào)用 deleteFolderRecursive 函數(shù)以刪除整個(gè)目錄及其所有內(nèi)容。
刪除導(dǎo)入語(yǔ)句
function deleteComponentFromIndex(component, indexPath) {
const upper = getFirstLetterUpper(component);
const importStr = `${getImportStr(upper, component)}\n`;
let data = fs.readFileSync(indexPath).toString();
data = data.replace(new RegExp(importStr), () => '').replace(new RegExp(` ${upper},\n`), '');
fs.writeFile(indexPath, data, (err) => {
if (err) {
utils.log(err, 'error');
} else {
utils.log(`${component} has been removed from /src/index.ts`, 'success');
}
});
}
該函數(shù)接受兩個(gè)參數(shù): component 和 indexPath。
- component參數(shù)是要?jiǎng)h除的組件的名稱
- indexPath 參數(shù)是項(xiàng)目索引文件的路徑。
該函數(shù)首先使用 getImportStr 函數(shù),使用變量(組件名稱的大寫版本)為組件生成 import 語(yǔ)句。然后,它使用 fs.readFileSync 函數(shù)讀取索引文件的內(nèi)容,并在文件中搜索 import 語(yǔ)句和組件名。
如果找到 import 語(yǔ)句或組件名稱,函數(shù)將使用 String.place 函數(shù)將其替換為空字符串。最后,函數(shù)使用 fs.writeFile 函數(shù)將修改后的索引文件內(nèi)容寫回文件。如果在此過程中發(fā)生錯(cuò)誤,該函數(shù)將一條錯(cuò)誤消息記錄到控制臺(tái)。否則,它將記錄一條成功消息,指示組件已從索引文件中刪除。
總結(jié)
通過本次章節(jié)的學(xué)習(xí),學(xué)習(xí)到了動(dòng)態(tài)修改文件內(nèi)容以及根據(jù)模板生成組件文件的方式。
以上就是tdesign vue初始化組件源碼解析的詳細(xì)內(nèi)容,更多關(guān)于tdesign vue初始化組件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
前端實(shí)現(xiàn)不同角色登入展示不同頁(yè)面效果實(shí)例
要實(shí)現(xiàn)不同角色登錄跳轉(zhuǎn)不同的前端頁(yè)面,可以在登錄成功后,根據(jù)用戶的角色信息,使用路由跳轉(zhuǎn)到不同的頁(yè)面,這篇文章主要給大家介紹了關(guān)于前端實(shí)現(xiàn)不同角色登入展示不同頁(yè)面效果的相關(guān)資料,需要的朋友可以參考下2024-08-08
詳解vue中點(diǎn)擊空白處隱藏div的實(shí)現(xiàn)(用指令實(shí)現(xiàn))
本篇文章主要介紹了詳解vue中點(diǎn)擊空白處隱藏div的實(shí)現(xiàn)(用指令實(shí)現(xiàn)),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2018-04-04
從零開始在vue-cli4配置自適應(yīng)vw布局的實(shí)現(xiàn)
這篇文章主要介紹了從零開始在vue-cli4配置自適應(yīng)vw布局,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
vant list組件滾動(dòng)保留滾動(dòng)條位置
這篇文章主要介紹了vant list組件滾動(dòng)保留滾動(dòng)條位置,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
vue3 reactive定義的引用類型直接賦值導(dǎo)致數(shù)據(jù)失去響應(yīng)式問題
這篇文章主要介紹了vue3 reactive定義的引用類型直接賦值導(dǎo)致數(shù)據(jù)失去響應(yīng)式問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
vue+elementui(對(duì)話框中form表單的reset問題)
這篇文章主要介紹了vue+elementui(對(duì)話框中form表單的reset問題),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
解決Vue在封裝了Axios后手動(dòng)刷新頁(yè)面攔截器無(wú)效的問題
這篇文章主要介紹了解決VUE在封裝了Axios后手動(dòng)刷新頁(yè)面攔截器無(wú)效的問題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-11-11
Vue實(shí)現(xiàn)購(gòu)物車實(shí)例代碼兩則
這篇文章主要介紹了Vue實(shí)現(xiàn)購(gòu)物車實(shí)例代碼,需要的朋友可以參考下2020-05-05
使用Vue3新特性構(gòu)建動(dòng)態(tài)表單的方法詳解
傳統(tǒng)的表單開發(fā)通常需要編寫大量的重復(fù)代碼,例如處理用戶輸入、驗(yàn)證數(shù)據(jù)、更新 UI 等等,為了簡(jiǎn)化開發(fā),我們可以借助 Vue 3 的新特性,例如組合式 API 和 ref 對(duì)象,所以本文我們將一起學(xué)習(xí)如何使用 Vue 3 的新特性構(gòu)建一個(gè)更加靈活、可擴(kuò)展的動(dòng)態(tài)表單2024-06-06

