解放前端生产力,一手打造自己的表单代码生成器

解放前端生产力,一手打造自己的表单代码生成器手摸手教你打造一个支持内嵌网页的VS Code插件,实现Vue项目前端表单代码的自动生成,早日实现摸鱼自由。

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

效果展示

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

image

看完动图是不是提神了那么一丢丢,让我们开干吧~~ 343665c082dccb3918d3210edc2a1882.jpeg

第一步/Step 1

首先,我们需要一款开源拖拽式设计的可视化设计器,GitHub、码云一通搜索,已经有很多成品了,各种form-create、form-design、vue-form、form-generator等等;

其次,从上述设计器中筛选支持代码生成的,当然如果没有代码生成也可以自己实现,毕竟都开源了不是?

我这里选择的是开源的VForm设计器:VForm GitHub
为啥咧?哈哈。。。看着眼熟呗,功能上多那么一丢丢~~ 相信我,点一下上面链接,你还会回来点赞的

第二步/Step 2

安装VS Code插件开发套件:

npm install -g yo generator-code

安装成功后,运行yo code生成新的插件项目:

quick-coder-first.png

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

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

quick-coder-2.png

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

extension.js,插件扩展点描述文件
package.json,项目属性、依赖包及插件配置文件

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

第三步/Step 3

修改package.json,以增加插件的启动命令,可以从命令面板和左侧资源管理器启动。

"activationEvents": [
    "onCommand:extension.openVFormMaker"
],
"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文件。
  1. 那么问题来了?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

整个quick-coder插件项目源码已推送,需要的大佬们自取(记得顺手给个Star哟):GitHub

今天的文章解放前端生产力,一手打造自己的表单代码生成器分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:http://bianchenghao.cn/17904.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注