关于vue.js:解放前端生产力一手打造自己的表单代码生成器

2次阅读

共计 5296 个字符,预计需要花费 14 分钟才能阅读完成。

本文指标:手摸手教你打造一个反对内嵌网页的 VS Code 插件,实现 Vue 我的项目前端表单代码的主动生成,早日实现摸鱼自在。

成果展现

废话不多说,先看看最终的工作成绩:

看完动图是不是提神了那么一丢丢,让咱们开干吧~~

第一步 /Step 1

首先,咱们须要一款 开源 拖拽式设计 的可视化设计器,GitHub、码云一通搜寻,曾经有很多成品了,各种 form-create、form-design、vue-form、form-generator 等等;<br/>

其次,从上述设计器中筛选反对代码生成的,当然如果没有代码生成也能够本人实现,毕竟都开源了不是?

我这里抉择的是开源的 VForm 设计器:VForm GitHub
为啥咧?哈哈。。。看着眼生呗,性能上多那么一丢丢~~

第二步 /Step 2

装置 VS Code 插件开发套件:

npm install -g yo generator-code

装置胜利后,运行 yo code 生成新的插件我的项目:

起个简略又好听的名字——quick-coder(撸码达人),加个简略的阐明,其余选项按需抉择即可。

来来来,看一下生成的插件我的项目:

这里只须要重点关注两个文件:extension.jspackage.json

extension.js,插件扩大点形容文件
package.json,我的项目属性、依赖包及插件配置文件

第二步工作告一段落,接下来开始第三步插件的编码实现工作。

第三步 /Step 3

批改 package.json,以减少插件的启动命令,能够从命令面板和左侧资源管理器启动。

"contributes": {
    "commands": [{
        "command": "extension.openVFormMaker",
        "title": "关上 VForm 设计器"
    }],
    "menus": {
        "explorer/context": [{
            "command": "extension.openVFormMaker",
            "group": "navigation"
        }]
    }
},

批改 extension.js 的插件启用办法,仅一行:

function activate(context) {require('./src/vform-loader')(context)
}

截止到此时,咱们尚未解释整个代码生成器插件是如何工作的,但当初到了不得不说的时候了。
咱们心愿,当插件启动的时候关上一个 WebView 面板,WebView 面板通过 URL 配置参数加载 VForm 网页,当 VForm 生成代码时与 VS Code 通过 postMessage 通信,VS Code 负责将生成代码保留为本地文件。
实现上述需要的要害代码都在 vform-loader.js 文件中

这里还有两个小问题须要解答:

  1. WebView 能间接加载近程网页吗?
    答案是 不能,只能加载本地 HTML 文件。
  2. 那么问题来了?WebView 怎么加载远端网页的 HTML 呢?
    答案也很 简略,就是在本地 HTML 文件内嵌入 iframe,iframe 万能——YYDS!

解决了上述几个小 case,咱们来看看整个插件的灵魂代码。

src\view\index.html

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width,initial-scale=0,maximum-scale=0,user-scalable=yes,shrink-to-fit=no"
    />
    <title>Quick Coder</title>
  </head>

  <body>
    <iframe id="frame" width="100%" height="100%" frameborder="0"></iframe>
    <script>
      window.onload = function () {const vscode = acquireVsCodeApi();
        const cmds = {setSrc: function (message) {var frame = document.getElementById("frame");
            frame.src = message.data.src;
          },
          writeFile: function (message) {vscode.postMessage(message);
          },
          openUrl: function (message) {vscode.postMessage(message);
          },
          setStorageItem: function (message) {vscode.postMessage(message);
          },
        };

        window.addEventListener("message", (event) => {
          const message = event.data;
          if (message && message.cmd) cmds[message.cmd](message);
        });
      };
    </script>
  </body>
</html>

src\vform-loader.js

const vscode = require('vscode')
const fs = require('fs')
const path = require('path')
const open = require('open')
const DB_PATH = path.join(__dirname,'./data/db.json')

function getExtensionFileAbsolutePath(context, relativePath) {return path.join(context.extensionPath, relativePath)
}

/**
 * 从某个 HTML 文件读取能被 Webview 加载的 HTML 内容
 * @param {*} context 上下文
 * @param {*} templatePath 绝对于插件根目录的 html 文件相对路径
 */
function getWebViewContent(context, templatePath) {const resourcePath = getExtensionFileAbsolutePath(context, templatePath)
    const dirPath = path.dirname(resourcePath)
    let html = fs.readFileSync(resourcePath, 'utf-8')
    // vscode 不反对间接加载本地资源,须要替换成其专有门路格局,这里只是简略的将款式和 JS 的门路替换
    html = html.replace(/(<link.+?href="|<script.+?src="|<img.+?src=")(.+?)"/g, (m, $1, $2) => {return $1 + vscode.Uri.file(path.resolve(dirPath, $2)).with({scheme: 'vscode-resource'}).toString() + '"'})
    return html
}

const methods = {writeFile: function (message, vscode, dirPath) {let { fileName, code} = message.data
        let filePath = path.join(dirPath, fileName)
        fs.writeFileSync(filePath, code)
        vscode.window.showInformationMessage(` 文件 ${fileName}创立胜利 `)
    },
    openUrl: function (message, vscode, dirPath) {open(message.data.url)
    },
    setStorageItem: function(message, vscode, dirPath) {const { key, val} = message.data
        const str = fs.readFileSync(DB_PATH).toString()
        let json = {}
        if (str) {json = JSON.parse(str)
        }
        json[key] = val
        fs.writeFileSync(DB_PATH, JSON.stringify(json))
    },
}

module.exports = function (context) {context.subscriptions.push(vscode.commands.registerCommand('extension.openVFormMaker', (uri) => {if (uri) {
            let dirPath = uri.fsPath,
                stat = fs.lstatSync(dirPath)
            if (stat.isFile()) dirPath = path.dirname(dirPath)

            let pclintBar = vscode.window.createStatusBarItem()
            pclintBar.text = ` 指标文件夹:${dirPath}`
            pclintBar.show()

            const panel = vscode.window.createWebviewPanel(
                'vFormMaker',
                "VForm 表单设计器",
                vscode.ViewColumn.One,
                {
                    enableScripts: true, // 启用 JS,默认禁用
                    retainContextWhenHidden: true, // webview 被暗藏时放弃状态,防止被重置
                }
            )
            panel.onDidChangeViewState(e => {if (panel.visible) {pclintBar.show()
                } else {pclintBar.hide()
                }
            })
            panel.webview.html = getWebViewContent(context, 'src/view/index.html')
            panel.webview.postMessage({
                cmd: 'setSrc',
                data: {src: vscode.workspace.getConfiguration().get('VFormMaker.url') + '&t=' + new Date(),
                    db: JSON.parse(fs.readFileSync(DB_PATH).toString() || '{}')
                }
            })
            panel.webview.onDidReceiveMessage(message => {if (message.cmd && message.data) {let method = methods[message.cmd]
                    if (method) method(message, vscode, dirPath)
                } else {vscode.window.showInformationMessage(` 没有与音讯对应的办法 `)
                }
            }, undefined, context.subscriptions)
            panel.onDidDispose(e => {pclintBar.dispose()
            })
        } else {vscode.window.showInformationMessage(` 无奈获取文件夹门路 `)
        }
    }))
}

OK~ 灰常好,给看到这里的大佬们鼓掌👏👏👏,行将看到插件运行成果!!

最初批改 package.json 文件的 contributes 属性,减少一个 URL 参数配置,竣工!!

"contributes": {
    "configuration": {
        "type": "object",
        "title": "VForm 设计器配置",
        "properties": {
            "VFormMaker.url": {
                "type": "string",
                "default": "http://120.92.142.115/?vscode=1",
                "description": "VForm 设计器近程 URL"
            }
        }
    },
    

连忙在 VS Code 中按下 F5 键调试插件,观赏下本人的工作成绩😤😤~~~

第四步 / 打包公布

装置打包工具 vsce

npm install -g vsce

在插件我的项目运行 vsce package 命令,即可生成.vsix 文件(会提醒批改 README.md 文件,减少插件的简介及应用阐明)

vsce package

注册 VS marketplace 账号,上传.vsix 文件,凋谢给所有 VS Code 用户应用:
VS marketplace

后话 /Finally

简略回顾一下,咱们通过 WebView 嵌入 VForm 的远端网页,实现了常见的 Vue 表单前端代码生成(反对 Vue2 也反对 Vue3 哦)的预期需要,因为 VForm 自身是一个开源我的项目,且有良好的扩展性,有心的大佬们能够自在扩大 VForm 的性能,进一步实现 el-table 等更多组件的前端代码主动生成,早日实现摸鱼自在🍺🍺🍺

最初的最初

感觉本人写插件有点小累的大佬们,能够间接在 VS Code 扩大中搜寻 vform-makervformAdmin

最初,再附上寰球最大同性交友网的 VForm 链接:GitHub
国内同步码云:Gitee

正文完
 0