使用vue時,每次導入組件都十分的麻煩,得先寫明組件標籤,而後在script標籤中import導入,在components中顯式聲明。。。遇到這種勞動重複性問題時,我都會想是否能用腳本完成?有幸使用了vscode,能夠自定義打造咱們的自動導入插件vue
使用yo code
初始化項目。百度上關於初始化項目一大堆,不重點說了。。node
第一步就是要先能自動提示組件名稱,vscode中關於顯示建議的核心API是( 看API直接ctrl+左鍵點擊const vscode = require('vscode') 便可,d.ts描述文件比官網API文檔都詳細 )json
export function registerCompletionItemProvider(selector: DocumentSelector, provider: CompletionItemProvider, ...triggerCharacters: string[]): Disposable;
其中: CompletionItemProvider
包含provideCompletionItems
和resolveCompletionItem
.編輯器
provideCompletionItems
返回選項集合(暫時這麼叫吧),resolveCompletionItem
具體處理你選擇選項時的事件ide
根目錄下新建autotip.js文件, 具體用法見註釋測試
const vscode = require('vscode'); const fs = require('fs'); module.exports = function (context) { let rangeline = 0 let rangeCol = 0 /** * 只支持單文件夾! * @param {*} document * @param {*} position */ function provideCompletionItems(document, position) { let arr = []; // 遞歸尋找組件名 let readFile = (fileDir, filter) => { let filearr = fs.readdirSync(fileDir) filearr.forEach((v) => { if (fs.statSync(fileDir + '/' + v).isDirectory()) { readFile(fileDir + '/' + v, filter) } else { if (v.indexOf(filter) !== -1 && v.substring(v.lastIndexOf('.') + 1) === 'vue') { arr.push(v.substring(0, v.lastIndexOf('.'))) } } }) } // 找到光標所在的一行 const line = document.lineAt(position); const lineText = line.text.substring(0, position.character); rangeline = position.line rangeCol = position.character let workspaceFolders = vscode.workspace.workspaceFolders.map(item => item.uri.path); // 找到根目錄 let rootpath = workspaceFolders[0]; // 遞歸尋找src目錄下的vue文件 readFile(rootpath.substring(1) + '/src', lineText.substring(lineText.indexOf('<') + 1)); // 返回全部vue文件 return arr.map((v) => { return new vscode.CompletionItem(v, vscode.CompletionItemKind.Field); }) } function resolveCompletionItem(item) { // 把vue文件名處理成xxx-xxx的形式 let content = item.label[0].toLowerCase() + item.label.substring(1) content = content.replace(/[A-Z]/g, (text) => { return `-${text.toLowerCase()}` }) item.insertText = content return item; } context.subscriptions.push(vscode.languages.registerCompletionItemProvider('vue', { provideCompletionItems, resolveCompletionItem }, '<')); // 觸發建議的按鍵 };
完成後,在extension.js
中引入ui
// The module 'vscode' contains the VS Code extensibility API // Import the module and reference it with the alias vscode in your code below const vscode = require('vscode'); const autotip = require('./autptip') // this method is called when your extension is activated // your extension is activated the very first time the command is executed function activate(context) { // Use the console to output diagnostic information (console.log) and errors (console.error) // This line of code will only be executed once when your extension is activated console.log('Congratulations, your extension "autotip" is now active!'); // The command has been defined in the package.json file // Now provide the implementation of the command with registerCommand // The commandId parameter must match the command field in package.json // 引入 autotip(context) } exports.activate = activate; // this method is called when your extension is deactivated function deactivate() { } exports.deactivate = deactivate;
在package.json
中註冊this
"activationEvents": [ "onLanguage:vue" ],
如今你能夠按F5測試,是否生成了建議列表spa
按下tab或者enter時觸發如下動做:插件
import xxx from 'xxxx'
模板萬變不離其中,都是用nodejs的IO文件流完成工做
先寫幾個通用方法
// 找到過濾文件 let readFile = (fileDir, filter) => { let filearr = fs.readdirSync(fileDir) filearr.forEach((v) => { if (fs.statSync(fileDir + '/' + v).isDirectory()) { readFile(fileDir + '/' + v, filter) } else { let reg = new RegExp(filter, 'i'); // 忽略大小寫 if (reg.test(v) && v.substring(v.lastIndexOf('.') + 1) === 'vue' && v.length === filter.length + 4) { obj.name = v.substring(0, v.lastIndexOf('.')) obj.path = fileDir + '/' + v.substring(0, v.lastIndexOf('.')) } } }) } // 找到某個字符串在編輯器中的行號 let getLineNumber = (filter) => { let scriptline = -1; for (let i = 0; i < document.lineCount; i++) { let str = document.lineAt(i).text; if (str.trim().indexOf(filter) !== -1) { scriptline = i; break; } } return scriptline; }
找到script標籤的位置以下:
let scriptline = getLineNumber('<script>');
complementtag.js具體代碼
const vscode = require('vscode'); const fs = require('fs'); const os = require('os') module.exports = function (context) { let rangeline = 0 let rangeCol = 0 function provideCompletionItems(document, position) { let obj = {}; let readFile = (fileDir, filter) => { let filearr = fs.readdirSync(fileDir) filearr.forEach((v) => { if (fs.statSync(fileDir + '/' + v).isDirectory()) { readFile(fileDir + '/' + v, filter) } else { let reg = new RegExp(filter, 'i'); if (reg.test(v) && v.substring(v.lastIndexOf('.') + 1) === 'vue' && v.length === filter.length + 4) { obj.name = v.substring(0, v.lastIndexOf('.')) obj.path = fileDir + '/' + v.substring(0, v.lastIndexOf('.')) } } }) } let getLineNumber = (filter) => { let scriptline = -1; for (let i = 0; i < document.lineCount; i++) { let str = document.lineAt(i).text; if (str.trim().indexOf(filter) !== -1) { scriptline = i; break; } } return scriptline; } rangeline = position.line rangeCol = position.character let item = document.getText(new vscode.Range(new vscode.Position(rangeline, 0), new vscode.Position(rangeline, rangeCol))); item = item.trim() item = item.substring(1, item.length - 1) item = item.replace(/-/g, '') let workspaceFolders = vscode.workspace.workspaceFolders.map(item => item.uri.path); let rootpath = workspaceFolders[0]; readFile(rootpath.substring(1) + '/src', item) let scriptline = getLineNumber('<script>'); // 完成import部分 vscode.window.activeTextEditor.edit(editBuilder => { const text = `import ${obj.name} from '${obj.path.substring(obj.path.indexOf('src'))}'` editBuilder.insert(new vscode.Position(scriptline + 1, 0), text + os.EOL); // 尋找components字符所在行 let componentsLine = getLineNumber('components'); if (componentsLine !== -1) { let old = document.lineAt(componentsLine).text console.log(old.trim().indexOf('{')) console.log('總長度' + old.trim().length - 1) // 存在components選項 let i = document.lineAt(componentsLine).text.trim().indexOf('components') if (i === 0) { if (old.trim().indexOf('{') === old.trim().length - 1) { // components: { 格式 const text = `${obj.name},${os.EOL}`; editBuilder.insert(new vscode.Position(componentsLine + 1, 0), text) } else { // components: { }, 格式 const text = old.substring(0, old.length - 2) + ',' + obj.name + '},' + os.EOL; editBuilder.replace(new vscode.Range(new vscode.Position(componentsLine, 0), new vscode.Position(componentsLine + 1, 0)), text) } } } else { // 沒有components選項 const text = `components: { ${obj.name} },${os.EOL}` editBuilder.replace(new vscode.Range(new vscode.Position(componentsLine, 0), new vscode.Position(componentsLine + 1, 0)), text) } }); } function resolveCompletionItem(item) { return item; } context.subscriptions.push(vscode.languages.registerCompletionItemProvider('vue', { provideCompletionItems, resolveCompletionItem }, '>')); };
如法炮製,在extension.js
引入
// The module 'vscode' contains the VS Code extensibility API // Import the module and reference it with the alias vscode in your code below const vscode = require('vscode'); const autotip = require('./autptip') const complementtag = require('./complementtag') // this method is called when your extension is activated // your extension is activated the very first time the command is executed function activate(context) { // Use the console to output diagnostic information (console.log) and errors (console.error) // This line of code will only be executed once when your extension is activated console.log('Congratulations, your extension "autotip" is now active!'); // The command has been defined in the package.json file // Now provide the implementation of the command with registerCommand // The commandId parameter must match the command field in package.json autotip(context) complementtag(context) } exports.activate = activate; // this method is called when your extension is deactivated function deactivate() { } exports.deactivate = deactivate;
能夠直接在vscode中搜索autotip
這個插件,固然這個插件有不少不完善的地方,可是最重要的怎麼本身學會去寫插件,本身寫插件本身以爲方便就好。別人寫插件考慮的天然是本身工做中的問題。
由於是根據components
這個字符串做爲判斷依據的,只要你其餘出現了components這個字眼,那麼這個插件就有問題,還有這個插件只支持單文件夾工做空間,儘管有這麼多問題可是我卻用的很舒服,由於我工做中不會遇到這些問題,若是有一天遇到了就再改一下嘛。插件這東西方便就好,因此本身寫適合本身的插件是多麼重要啊