1
0
mirror of https://github.com/sahadev/vue-component-creater-ui.git synced 2025-06-06 13:04:05 +08:00

update: 完全升级Vue3过程中的记录

This commit is contained in:
shangbin 2021-11-30 19:17:29 +08:00
parent 23bb007b5b
commit d6f575c503
26 changed files with 1032 additions and 463 deletions

13
index.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

999
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@
], ],
"main": "./dist/vcc.umd.min.js", "main": "./dist/vcc.umd.min.js",
"scripts": { "scripts": {
"dev": "vite --port 8008",
"serve": "vue-cli-service serve --open --port 8008", "serve": "vue-cli-service serve --open --port 8008",
"build:release": "vue-cli-service build", "build:release": "vue-cli-service build",
"build": "vue-cli-service build --report --target lib --name vcc './src/components-v2/VCC.vue' && node ./src/script/distClear.js", "build": "vue-cli-service build --report --target lib --name vcc './src/components-v2/VCC.vue' && node ./src/script/distClear.js",
@ -22,36 +23,41 @@
}, },
"dependencies": { "dependencies": {
"@babel/parser": "^7.11.5", "@babel/parser": "^7.11.5",
"ant-design-vue": "^1.7.2", "@originjs/vite-plugin-require-context": "^1.0.9",
"@vitejs/plugin-vue": "^1.10.0",
"@vue/compat": "^3.2.22",
"@vue/compiler-sfc": "^3.2.22",
"axios": "^0.21.4", "axios": "^0.21.4",
"copy-to-clipboard": "^3.3.1", "copy-to-clipboard": "^3.3.1",
"core-js": "^3.6.4", "core-js": "^3.6.4",
"crypto-random-string": "^3.3.0", "crypto-random-string": "^3.3.0",
"css": "^3.0.0", "css": "^3.0.0",
"element-ui": "^2.15.6", "element-plus": "^1.2.0-beta.3",
"escodegen": "^2.0.0", "escodegen": "^2.0.0",
"espree": "^7.3.0", "espree": "^7.3.0",
"eventemitter3": "^4.0.7", "eventemitter3": "^4.0.7",
"fast-xml-parser": "^3.17.4", "fast-xml-parser": "^3.17.4",
"file-saver": "^2.0.2", "file-saver": "^2.0.2",
"fs-extra": "^9.0.1", "fs-extra": "^9.0.1",
"get-own-enumerable-property-symbols": "^3.0.2",
"glob": "^7.1.6", "glob": "^7.1.6",
"html2canvas": "^1.0.0-rc.7", "html2canvas": "^1.0.0-rc.7",
"is-absolute-url": "^3.0.3", "is-absolute-url": "^3.0.3",
"keymaster": "^1.6.2", "keymaster": "^1.6.2",
"lodash": "^4.17.20", "lodash-es": "^4.17.21",
"md5": "^2.3.0", "md5": "^2.3.0",
"modern-normalize": "^1.0.0", "modern-normalize": "^1.0.0",
"object-inspect": "^1.11.0",
"parse-package-name": "^0.1.0", "parse-package-name": "^0.1.0",
"prettier": "^2.4.0", "prettier": "^2.4.0",
"prismjs": "^1.20.0", "prismjs": "^1.20.0",
"query-string": "^6.13.7", "query-string": "^6.13.7",
"register-service-worker": "^1.6.2", "register-service-worker": "^1.6.2",
"split.js": "^1.6.2", "split.js": "^1.6.2",
"stringify-object": "^3.3.0",
"vant": "^2.10.7", "vant": "^2.10.7",
"view-design": "^4.3.2", "view-design": "^4.3.2",
"vue": "^2.6.14", "vite": "^2.6.14",
"vue": "^3.2.22",
"vue-codemirror": "^4.0.6", "vue-codemirror": "^4.0.6",
"vue-nestable": "^2.6.0", "vue-nestable": "^2.6.0",
"vue-router": "^3.4.9", "vue-router": "^3.4.9",
@ -72,7 +78,9 @@
"lint-staged": "^9.5.0", "lint-staged": "^9.5.0",
"sass": "^1.25.0", "sass": "^1.25.0",
"sass-loader": "^8.0.2", "sass-loader": "^8.0.2",
"vue-template-compiler": "^2.6.14" "vue-template-compiler": "^2.6.14",
"is-obj": "^3.0.0",
"is-regexp": "^3.0.0"
}, },
"eslintConfig": { "eslintConfig": {
"root": true, "root": true,

View File

@ -3,12 +3,13 @@
</template> </template>
<script> <script>
import { defineAsyncComponent } from 'vue'
// VCC // VCC
const initCodeStr = '{"template":{"lc_id":"root","__children":[{"div":{"class":"container","style":"min-height: 100%; padding-bottom: 100px;","lc_id":"container","__text__":"Hello欢迎使用LCG请往此区域拖拽组件","__children":[{"el-button":{"lc-mark":"","type":"danger","lc_id":"COAAYXizyI","__children":[],"__text__":"危险按钮","@click":"onButtonClick","size":"small"}}]}}]}}' const initCodeStr = '{"template":{"lc_id":"root","__children":[{"div":{"class":"container","style":"min-height: 100%; padding-bottom: 100px;","lc_id":"container","__text__":"Hello欢迎使用LCG请往此区域拖拽组件","__children":[{"el-button":{"lc-mark":"","type":"danger","lc_id":"COAAYXizyI","__children":[],"__text__":"危险按钮","@click":"onButtonClick","size":"small"}}]}}]}}'
export default { export default {
components: { components: {
vcc: () => import('./components-v2/VCC.vue'), vcc: defineAsyncComponent(() => import('./components-v2/VCC.vue')),
}, },
data() { data() {
return { return {

View File

@ -16,7 +16,7 @@
</div> </div>
</div> </div>
<attribute-input :enableRemoveButton="true" class="attribute" @save="onSaveAttr" @remove="onRemove" <attribute-input :enableRemoveButton="true" class="attribute" @save="onSaveAttr" @remove="onRemove"
ref="attributeInput" shortcutInitMode="hand" @codeRefresh="generateVueCode" style="display:none;" ref="attributeInput" shortcutInitMode="hand" @codeRefresh="generateVueCode"
:__rawVueInfo__="currentEditRawInfo"> :__rawVueInfo__="currentEditRawInfo">
</attribute-input> </attribute-input>
</div> </div>
@ -41,19 +41,21 @@
<el-tooltip effect="dark" content="清空当前编辑内容" placement="top-start"> <el-tooltip effect="dark" content="清空当前编辑内容" placement="top-start">
<el-popconfirm confirmButtonText="确认" cancelButtonText="点错了" icon="el-icon-info" iconColor="red" <el-popconfirm confirmButtonText="确认" cancelButtonText="点错了" icon="el-icon-info" iconColor="red"
title="点我将清空所有编辑的内容, 确认吗?" @onConfirm="clear"> title="点我将清空所有编辑的内容, 确认吗?" @onConfirm="clear">
<img slot="reference" class="round-icon" :src="iconClear" alt=""> <template #reference>
<img class="round-icon" :src="iconClear" alt="">
</template>
</el-popconfirm> </el-popconfirm>
</el-tooltip> </el-tooltip>
</div> </div>
<div> <div>
<lc-code :rawCode="code" :codeDialogVisible.sync="codeDialogVisible"> <lc-code :rawCode="code" v-model:codeDialogVisible="codeDialogVisible">
</lc-code> </lc-code>
<code-structure @save="onSaveAttr" @remove="onRemove" ref="codeStructure" :visible.sync="structureVisible" <code-structure @save="onSaveAttr" @remove="onRemove" ref="codeStructure" v-model="structureVisible"
@codeRefresh="generateVueCode" @onLevelChange="onLevelChange"> @codeRefresh="generateVueCode" @onLevelChange="onLevelChange">
</code-structure> </code-structure>
<CodeEditor :codeDialogVisible.sync="jsDialogVisible" @saveJSCode="saveJSCode"></CodeEditor> <CodeEditor v-model:codeDialogVisible="jsDialogVisible" @saveJSCode="saveJSCode"></CodeEditor>
<VueEditor :vueDialogVisible.sync="vueDialogVisible" @codeParseSucess="codeParseSucess"></VueEditor> <VueEditor v-model:vueDialogVisible="vueDialogVisible" @codeParseSucess="codeParseSucess"></VueEditor>
</div> </div>
<!-- 辅助定位线 --> <!-- 辅助定位线 -->
@ -64,24 +66,24 @@
</template> </template>
<script> <script>
import { defineAsyncComponent } from 'vue'
import { splitInit } from "../libs/split-init"; import { splitInit } from "../libs/split-init";
// // //
import { MainPanelProvider } from "../libs/main-panel"; import { MainPanelProvider } from "../libs/main-panel";
import { initContainerForLine } from "@/utils/lineHelper"; import { initContainerForLine } from "@/utils/lineHelper";
import keymaster from "keymaster"
const keymaster = require('keymaster');
export default { export default {
name: "vcc", name: "vcc",
props: ['initCodeEntity'], props: ['initCodeEntity'],
components: { components: {
RawComponents: () => import("../components/RawComponents"), RawComponents: defineAsyncComponent(() => import("@/components/RawComponents.vue")),
ToolsBar: () => import("./ToolsBar"), ToolsBar: defineAsyncComponent(() => import("./ToolsBar")),
AttributeInput: () => import("../components/AttributeInput"), AttributeInput: defineAsyncComponent(() => import("../components/AttributeInput")),
CodeStructure: () => import("../components/CodeStructure"), CodeStructure: defineAsyncComponent(() => import("../components/CodeStructure")),
"lc-code": () => import("../components/Code"), "lc-code": defineAsyncComponent(() => import("../components/Code")),
CodeEditor: () => import('../components/JSCodeEditorDialog.vue'), CodeEditor: defineAsyncComponent(() => import('../components/JSCodeEditorDialog.vue')),
VueEditor: () => import('../components/VueCodeParseDialog.vue') VueEditor: defineAsyncComponent(() => import('../components/VueCodeParseDialog.vue'))
}, },
data() { data() {
return { return {
@ -101,7 +103,7 @@ export default {
currentEditRawInfo(newValue) { currentEditRawInfo(newValue) {
const attributeContainter = document.querySelector(".attribute"); const attributeContainter = document.querySelector(".attribute");
if (newValue) { if (newValue) {
attributeContainter.style = "right:10px;"; attributeContainter.style = "right:10px; display:block;";
this.$refs['attributeInput'].onShow(); this.$refs['attributeInput'].onShow();
} else { } else {
attributeContainter.style = "right: calc(-300px - 20px); display:none;"; attributeContainter.style = "right: calc(-300px - 20px); display:none;";

View File

@ -1,11 +1,11 @@
<template> <template>
<el-card class="attribute-container"> <el-card class="attribute-container">
<center> <div style="text-algin: center;">
<el-switch v-model="editMode" active-text="自由编辑" inactive-text="约束编辑" active-color="#13ce66" <el-switch v-model="editMode" active-text="自由编辑" inactive-text="约束编辑" active-color="#13ce66"
inactive-color="#13ce66"> inactive-color="#13ce66">
</el-switch> </el-switch>
</center> </div>
<div style="margin-top: 20px;"> <div style="margin-top: 20px;">
<div name="1" v-show="!editMode"> <div name="1" v-show="!editMode">
@ -44,8 +44,8 @@
</div> </div>
</div> </div>
<center style="margin-top: 10px;"> <div style="margin-top: 10px;text-align:center;">
<el-tooltip class="item" effect="dark" content="新增属性 ctrl+a" placement="bottom"> <!-- <el-tooltip class="item" effect="dark" content="新增属性 ctrl+a" placement="bottom">
<el-button type="primary" class="center" @click="createNew" icon="el-icon-circle-plus-outline" circle> <el-button type="primary" class="center" @click="createNew" icon="el-icon-circle-plus-outline" circle>
</el-button> </el-button>
</el-tooltip> </el-tooltip>
@ -60,12 +60,11 @@
<el-button v-if="enableBroButton" type="primary" class="center" icon="el-icon-copy-document" @click="copyBro" <el-button v-if="enableBroButton" type="primary" class="center" icon="el-icon-copy-document" @click="copyBro"
circle> circle>
</el-button> </el-button>
</el-tooltip> </el-tooltip> -->
<div style="text-algin: center;">
<center>
<span class="shortcut-tip">支持快捷键操作</span> <span class="shortcut-tip">支持快捷键操作</span>
</center> </div>
</center> </div>
</el-card> </el-card>
</template> </template>
@ -73,7 +72,7 @@
<script> <script>
import { getRawComponentKey, getRawComponentContent } from "@/utils/common"; import { getRawComponentKey, getRawComponentContent } from "@/utils/common";
import { brotherEleEnum, copyBroCode } from "@/libs/bro-ele-config"; import { brotherEleEnum, copyBroCode } from "@/libs/bro-ele-config";
const keymaster = require('keymaster'); import keymaster from "keymaster"
export default { export default {
props: ['__rawVueInfo__', 'enableRemoveButton', 'shortcutInitMode'],// __rawVueInfo__, shortcutInitMode props: ['__rawVueInfo__', 'enableRemoveButton', 'shortcutInitMode'],// __rawVueInfo__, shortcutInitMode
@ -117,8 +116,6 @@ export default {
initShortcut() { initShortcut() {
console.log(`init by mode: ${this.shortcutInitMode}`) console.log(`init by mode: ${this.shortcutInitMode}`)
keymaster('⌘+a, ctrl+a', () => { keymaster('⌘+a, ctrl+a', () => {
if (this.enable) { if (this.enable) {
this.createNew(); this.createNew();

View File

@ -1,22 +1,21 @@
<template> <template>
<el-dialog title="代码预览" :visible.sync="codeDialogVisible" width="70%" top="10vh" :before-close="handleClose" <el-dialog title="代码预览" v-model="codeDialogVisible" width="70%" top="10vh" :before-close="handleClose" :center=true>
:center=true>
<pre style="max-height: 60vh;"> <pre style="max-height: 60vh;">
<code v-html="formatCode"></code> <code v-html="formatCode"></code>
</pre> </pre>
<div> <div>
<center style="color: #666; font-size: 12px;">使用代码前请确认相应的组件库已集成至项目</center> <div style="color: #666; font-size: 12px;text-align">使用代码前请确认相应的组件库已集成至项目</div>
</div> </div>
<span slot="footer"> <template v-slot:footer>
<span>
<el-tooltip effect="dark" content="拷贝" placement="left"> <el-tooltip effect="dark" content="拷贝" placement="left">
<img class="round-icon" :src="iconCopy" alt="" @click="copyCheck"> <img class="round-icon" :src="iconCopy" alt="" @click="copyCheck">
</el-tooltip> </el-tooltip>
<el-tooltip effect="dark" content="下载" placement="right"> <el-tooltip effect="dark" content="下载" placement="right">
<img class="round-icon" :src="iconDownload" alt="" @click="download"> <img class="round-icon" :src="iconDownload" alt="" @click="download">
</el-tooltip> </el-tooltip>
</span>
</span> </template>
</el-dialog> </el-dialog>
</template> </template>

View File

@ -50,12 +50,12 @@ import 'codemirror/addon/fold/indent-fold.js'
import 'codemirror/addon/fold/markdown-fold.js' import 'codemirror/addon/fold/markdown-fold.js'
import 'codemirror/addon/fold/xml-fold.js' import 'codemirror/addon/fold/xml-fold.js'
require(['axios'], axios => { // require(['axios'], axios => {
self.axios = axios.create({ // self.axios = axios.create({
baseURL: '', // baseURL: '',
timeout: 1000, // timeout: 1000,
}); // });
}); // });
export default { export default {
props: ['initCode', 'mode'], props: ['initCode', 'mode'],

View File

@ -1,19 +1,19 @@
<template> <template>
<el-drawer :visible.sync="drawer" :with-header="false" size="70%" direction="btt"> <el-drawer v-model="drawer" :with-header="false" size="70%" direction="btt">
<div class="container"> <div class="container">
<center>组件结构检视图 <div style="text-algin: center;">组件结构检视图
<br> <br>
<span style="font-size:12px;">Components <span style="font-size:12px;">Components
Structure</span> Structure</span>
</center> </div>
<el-row :gutter="20" style="height:0px;flex-grow:1;"> <el-row :gutter="20" style="height:0px;flex-grow:1;">
<el-col :span="16" style="height: 100%;"> <el-col :span="16" style="height: 100%;">
<div style="overflow: scroll;height:100%; margin: 0 20px;padding: 10px;"> <div style="overflow: scroll;height:100%; margin: 0 20px;padding: 10px;">
<vue-nestable v-model="treeData" @change="onLevelChange"> <vue-nestable v-model="treeData" @change="onLevelChange">
<template slot-scope="{ item }"> <template v-slot="{ item }">
<vue-nestable-handle :item="item"> <vue-nestable-handle :item="item">
<i class="el-icon-rank icon-s"></i> <i class="el-icon-rank icon-s"></i>
</vue-nestable-handle> </vue-nestable-handle>
@ -21,9 +21,9 @@
<span @click="onNodeClick(item)">{{ item.text }}</span> <span @click="onNodeClick(item)">{{ item.text }}</span>
</template> </template>
<div slot="placeholder"> <template v-slot:placeholder>
<b>The editor is empty.</b> <div><b>The editor is empty.</b></div>
</div> </template>
</vue-nestable> </vue-nestable>
</div> </div>

View File

@ -1,7 +1,7 @@
<template> <template>
<el-dialog title="JS逻辑编辑" :visible.sync="codeDialogVisible" width="70%" top="10vh" :before-close="handleClose" <el-dialog title="JS逻辑编辑" v-model="codeDialogVisible" width="70%" top="10vh" :before-close="handleClose"
:center=true> :center=true>
<CodeEditor style="max-height: 65vh;" ref="codeEditor" :initCode="code" mode="text/javascript"></CodeEditor> <!-- <CodeEditor style="max-height: 65vh;" ref="codeEditor" :initCode="code" mode="text/javascript"></CodeEditor> -->
<div style="text-align:center;padding: 10px;"> <div style="text-align:center;padding: 10px;">
<el-button type="primary" @click="onSave">确认修改</el-button> <el-button type="primary" @click="onSave">确认修改</el-button>
@ -14,12 +14,12 @@
<script> <script>
import dedent from 'dedent' import dedent from 'dedent'
import CodeEditor from './CodeEditor.vue' // import CodeEditor from './CodeEditor.vue'
export default { export default {
props: ['codeDialogVisible'], props: ['codeDialogVisible'],
components: { components: {
CodeEditor // CodeEditor
}, },
data() { data() {
@ -88,7 +88,7 @@ export default {
// //
}, },
handleClose() { handleClose() {
this.$emit("update:codeDialogVisible", false); // this.$emit("update:codeDialogVisible", false);
}, },
onSave() { onSave() {
const code = this.$refs.codeEditor.getEditorCode(); const code = this.$refs.codeEditor.getEditorCode();

View File

@ -34,11 +34,11 @@
</nav> </nav>
<nav v-if="currentSelectBrand.titleArray && currentSelectBrand.titleArray.length > 0"> <nav v-if="currentSelectBrand.titleArray && currentSelectBrand.titleArray.length > 0">
<center style="margin-bottom:10px;"> <div style="margin-bottom:10px;text-align:center;">
<div style="padding:5px;font-size:12px;color:grey;">快速查找需要的</div> <div style="padding:5px;font-size:12px;color:grey;">快速查找需要的</div>
<el-autocomplete class="inline-input" v-model="componentSearch" :fetch-suggestions="querySearch" size="mini" <el-autocomplete class="inline-input" v-model="componentSearch" :fetch-suggestions="querySearch" size="mini"
placeholder="请输入..." @select="handleSelect"></el-autocomplete> placeholder="请输入..." @select="handleSelect"></el-autocomplete>
</center> </div>
<div class="dismiss-scroll"> <div class="dismiss-scroll">
<div v-for="(item, index) in currentSelectBrand.titleArray" :key="item.title" class="second-nav" <div v-for="(item, index) in currentSelectBrand.titleArray" :key="item.title" class="second-nav"
:class="{'active':currentSelectBrand.selectIndex === index}" @click="selectSubnav(currentSelectBrand, index)"> :class="{'active':currentSelectBrand.selectIndex === index}" @click="selectSubnav(currentSelectBrand, index)">
@ -60,8 +60,8 @@
// import vant from "../rawComponents/vant"; // import vant from "../rawComponents/vant";
// import iview from "../rawComponents/iview"; // import iview from "../rawComponents/iview";
// import quasar from "../rawComponents/quasar"; // import quasar from "../rawComponents/quasar";
import raw from "../rawComponents/raw"; import raw from "../rawComponents/raw/index.vue";
import ele from "../rawComponents/element"; import ele from "../rawComponents/element/index.vue";
export default { export default {
data() { data() {
@ -94,7 +94,7 @@ export default {
enable: false enable: false
},], },],
currentIndex: 1 currentIndex: 0
}; };
}, },
methods: { methods: {

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog title="Vue二次编辑" :visible.sync="vueDialogVisible" width="70%" top="10vh" :before-close="handleClose" <el-dialog title="Vue二次编辑" v-model="vueDialogVisible" width="70%" top="10vh" :before-close="handleClose"
:center=true> :center=true>
<CodeEditor style="max-height: 65vh;" ref="codeEditor" :initCode="code" mode="text/html"></CodeEditor> <CodeEditor style="max-height: 65vh;" ref="codeEditor" :initCode="code" mode="text/html"></CodeEditor>

View File

@ -1,7 +1,7 @@
//该文件会遍历Object获取关键的class,事件,data, 最终拼装为一个完整的SFC文件 //该文件会遍历Object获取关键的class,事件,data, 最终拼装为一个完整的SFC文件
import stringifyObject from '@/libs/stringify-object'
import stringifyObject from 'stringify-object'; import merge from 'lodash-es/merge';
import _ from 'lodash'; import cloneDeep from 'lodash-es/cloneDeep';
import prettier from 'prettier/standalone.js'; import prettier from 'prettier/standalone.js';
import parserBabel from 'prettier/parser-babel.js'; import parserBabel from 'prettier/parser-babel.js';
@ -422,14 +422,6 @@ const scriptTemplate = `{
fillter: {}, fillter: {},
};`; };`;
const { merge, cloneDeep } = _;
const rawAdd = Set.prototype.add;
Set.prototype.add = function (value) {
if (typeof value === "string" && checkKeyword(value))
rawAdd.apply(this, arguments);
};
function checkKeyword(value) { function checkKeyword(value) {
return value != "true" && value != "false"; return value != "true" && value != "false";
} }
@ -499,7 +491,7 @@ function findVarFormExpression(expression) {
} }
} }
class CodeGenerator { export class CodeGenerator {
constructor(options = {}) { constructor(options = {}) {
this.options = options; this.options = options;
@ -629,23 +621,23 @@ class CodeGenerator {
classes.forEach((item) => { classes.forEach((item) => {
// 处理多个空字符串 // 处理多个空字符串
if (!item) return; if (!item) return;
this.classSet.add(item); this.classSet.addeee(item);
}); });
} else if (/^v-on/g.test(key) || /^@/g.test(key)) { } else if (/^v-on/g.test(key) || /^@/g.test(key)) {
// 匹配@,v-on // 匹配@,v-on
if (getVarName(value)) { if (getVarName(value)) {
this.methodSet.add(value); this.methodSet.addeee(value);
} }
} else if (/^v-/g.test(key) || /^:+/g.test(key)) { } else if (/^v-/g.test(key) || /^:+/g.test(key)) {
// 优先使Method消费因为有的:也是method // 优先使Method消费因为有的:也是method
if (this.options.checkIsMethodDirectives && this.options.checkIsMethodDirectives(key)) { if (this.options.checkIsMethodDirectives && this.options.checkIsMethodDirectives(key)) {
value = getVarName(value); value = getVarName(value);
value && this.methodSet.add(value); value && this.methodSet.addeee(value);
} else } else
// 业务侧可能会全部消费/^:+/g.test(key) // 业务侧可能会全部消费/^:+/g.test(key)
if (this.options.checkIsDataDirectives && this.options.checkIsDataDirectives(key)) { if (this.options.checkIsDataDirectives && this.options.checkIsDataDirectives(key)) {
value = getVarName(value); value = getVarName(value);
value && this.dataSet.add(value); value && this.dataSet.addeee(value);
} else { } else {
this.options.unSupportedKey && this.options.unSupportedKey(key, value); this.options.unSupportedKey && this.options.unSupportedKey(key, value);
} }
@ -655,7 +647,7 @@ class CodeGenerator {
// 用于匹配v-text {{}} // 用于匹配v-text {{}}
const temp = findVarFormExpression(value); const temp = findVarFormExpression(value);
temp.forEach((element) => { temp.forEach((element) => {
this.dataSet.add(element); this.dataSet.addeee(element);
}); });
} }
} else { } else {
@ -693,4 +685,15 @@ class CodeGenerator {
} }
} }
export { CodeGenerator };
const rawAdd = Set.prototype.add;
try {
//为何不能给add赋值且没有报错
Set.prototype.addeee = function (value) {
if (typeof value === "string" && checkKeyword(value))
rawAdd.apply(this, arguments);
};
// 经验证可以赋值,而代码会直接跳转至最后一行
} catch (error) {
console.error(error);
}

View File

@ -1,6 +1,5 @@
//该文件用于解析HTML输出为Object对象 //该文件用于解析HTML输出为Object对象
import htmlparser2 from "htmlparser2"
const htmlparser2 = require("htmlparser2");
function getNodeContent(node) { function getNodeContent(node) {
return node[Object.keys(node)[0]]; return node[Object.keys(node)[0]];

View File

@ -1,8 +1,7 @@
// 代码生成对象工厂,每次初始化需要获取一个新的实例,所以工厂方法模式最为适用 // 代码生成对象工厂,每次初始化需要获取一个新的实例,所以工厂方法模式最为适用
import { CodeGenerator } from "./bundle-core-esm"; import { CodeGenerator } from "./bundle-core-esm";
import { checkIsDataDirectives, checkIsMethodDirectives } from '@/libs/directiveCheck'; import { checkIsDataDirectives, checkIsMethodDirectives } from '@/libs/directiveCheck';
import stringifyObject from '@/libs/stringify-object'
const stringifyObject = require("stringify-object");
export function createNewCodeGenerator() { export function createNewCodeGenerator() {
return new CodeGenerator({ return new CodeGenerator({

View File

@ -9,8 +9,8 @@ import { parseComponent } from 'vue-template-compiler/browser';
import { merge, insertPresetAttribute, getSplitTag, replaceRowID, updateLinkTree, findCodeElemNode, findRawVueInfo, removeAllID } from "@/utils/forCode"; import { merge, insertPresetAttribute, getSplitTag, replaceRowID, updateLinkTree, findCodeElemNode, findRawVueInfo, removeAllID } from "@/utils/forCode";
import { getRawComponentContent, getRawComponentKey, isObject } from '@/utils/common'; import { getRawComponentContent, getRawComponentKey, isObject } from '@/utils/common';
import { createNewCodeGenerator } from "@/libs/code-generator-factory"; import { createNewCodeGenerator } from "@/libs/code-generator-factory";
const EventEmitter = require('eventemitter3'); import EventEmitter from 'eventemitter3'
const { cloneDeep } = require('lodash'); import { cloneDeep } from 'lodash-es';
/** /**
* 主控制面板辅助类用于代码的生成与绘制 * 主控制面板辅助类用于代码的生成与绘制
@ -64,17 +64,16 @@ export class MainPanelProvider {
let newScript = script.content.replace(/\s*export default\s*/, "") let newScript = script.content.replace(/\s*export default\s*/, "")
const componentOptions = (new Function(`return ${newScript}`))(); const componentOptions = (new Function(`return ${newScript}`))();
const render = compile(template.content);
const res = Vue.compile(template.content);
componentOptions.render = function () { componentOptions.render = function () {
const rootVNode = res.render.apply(this, arguments); const rootVNode = render.apply(this, arguments);
return rootVNode; return rootVNode;
}; };
componentOptions.staticRenderFns = res.staticRenderFns; // componentOptions.staticRenderFns = render.staticRenderFns;
// 渲染当前代码 // 渲染当前代码
new Vue(componentOptions).$mount(readyForMoutedElement); createBaseApp(componentOptions).mount(readyForMoutedElement);
// 拍平数据结构 // 拍平数据结构
this.editMode && this.flatDataStructure(rawDataStructure); this.editMode && this.flatDataStructure(rawDataStructure);

View File

@ -0,0 +1,139 @@
import isRegexp from 'is-regexp';
import isObject from 'is-obj';
const getOwnEnumPropSymbols = (object) => Object
.getOwnPropertySymbols(object)
.filter((keySymbol) => Object.prototype.propertyIsEnumerable.call(object, keySymbol));
export default function stringifyObject(input, options, pad) {
const seen = [];
return (function stringify(input, options = {}, pad = '') {
const indent = options.indent || '\t';
let tokens;
if (options.inlineCharacterLimit === undefined) {
tokens = {
newline: '\n',
newlineOrSpace: '\n',
pad,
indent: pad + indent,
};
} else {
tokens = {
newline: '@@__STRINGIFY_OBJECT_NEW_LINE__@@',
newlineOrSpace: '@@__STRINGIFY_OBJECT_NEW_LINE_OR_SPACE__@@',
pad: '@@__STRINGIFY_OBJECT_PAD__@@',
indent: '@@__STRINGIFY_OBJECT_INDENT__@@',
};
}
const expandWhiteSpace = string => {
if (options.inlineCharacterLimit === undefined) {
return string;
}
const oneLined = string
.replace(new RegExp(tokens.newline, 'g'), '')
.replace(new RegExp(tokens.newlineOrSpace, 'g'), ' ')
.replace(new RegExp(tokens.pad + '|' + tokens.indent, 'g'), '');
if (oneLined.length <= options.inlineCharacterLimit) {
return oneLined;
}
return string
.replace(new RegExp(tokens.newline + '|' + tokens.newlineOrSpace, 'g'), '\n')
.replace(new RegExp(tokens.pad, 'g'), pad)
.replace(new RegExp(tokens.indent, 'g'), pad + indent);
};
if (seen.includes(input)) {
return '"[Circular]"';
}
if (
input === null
|| input === undefined
|| typeof input === 'number'
|| typeof input === 'boolean'
|| typeof input === 'function'
|| typeof input === 'symbol'
|| isRegexp(input)
) {
return String(input);
}
if (input instanceof Date) {
return `new Date('${input.toISOString()}')`;
}
if (Array.isArray(input)) {
if (input.length === 0) {
return '[]';
}
seen.push(input);
const returnValue = '[' + tokens.newline + input.map((element, i) => {
const eol = input.length - 1 === i ? tokens.newline : ',' + tokens.newlineOrSpace;
let value = stringify(element, options, pad + indent);
if (options.transform) {
value = options.transform(input, i, value);
}
return tokens.indent + value + eol;
}).join('') + tokens.pad + ']';
seen.pop();
return expandWhiteSpace(returnValue);
}
if (isObject(input)) {
let objectKeys = [
...Object.keys(input),
...getOwnEnumPropSymbols(input),
];
if (options.filter) {
objectKeys = objectKeys.filter(element => options.filter(input, element));
}
if (objectKeys.length === 0) {
return '{}';
}
seen.push(input);
const returnValue = '{' + tokens.newline + objectKeys.map((element, i) => {
const eol = objectKeys.length - 1 === i ? tokens.newline : ',' + tokens.newlineOrSpace;
const isSymbol = typeof element === 'symbol';
const isClassic = !isSymbol && /^[a-z$_][$\w]*$/i.test(element);
const key = isSymbol || isClassic ? element : stringify(element, options);
let value = stringify(input[element], options, pad + indent);
if (options.transform) {
value = options.transform(input, element, value);
}
return tokens.indent + String(key) + ': ' + value + eol;
}).join('') + tokens.pad + '}';
seen.pop();
return expandWhiteSpace(returnValue);
}
input = String(input).replace(/[\r\n]/g, x => x === '\n' ? '\\n' : '\\r');
if (options.singleQuotes === false) {
input = input.replace(/"/g, '\\"');
return `"${input}"`;
}
input = input.replace(/\\?'/g, '\\\'');
return `'${input}'`;
})(input, options, pad);
}

View File

@ -1,19 +1,16 @@
import Vue from "vue"; import { createApp, compile } from "vue";
import ElementUI from "element-ui"; import ElementPlus from "element-plus";
import "element-ui/lib/theme-chalk/index.css"; import "element-plus/dist/index.css";
import AntdUI from "ant-design-vue";
import "ant-design-vue/dist/antd.css";
import APP from "./App.vue"; import APP from "./App.vue";
Vue.use(ElementUI); function createBaseApp(renderComponent = {}) {
Vue.use(AntdUI); const app = createApp(renderComponent);
app.use(ElementPlus);
return app;
}
createBaseApp(APP).mount("#app");
// 内部需要同样配置的全局Vue // 内部需要同样配置的全局Vue
self.Vue = Vue; self.createBaseApp = createBaseApp;
self.compile = compile;
new Vue({
el: "#app",
render: (h) => h(APP),
});

View File

@ -4,9 +4,9 @@
<div class="demonstration-element" lc_id="tr6tZHyaax" @click="dialogVisible = true">Dialog 对话框</div> <div class="demonstration-element" lc_id="tr6tZHyaax" @click="dialogVisible = true">Dialog 对话框</div>
<div lc-mark lc_id="KqRoagSJYH"> <div lc-mark lc_id="KqRoagSJYH">
<el-button type="text" lc_id="IbBWKHUvQx">直接拖我看结果</el-button> <el-button type="text" lc_id="IbBWKHUvQx">直接拖我看结果</el-button>
<el-dialog title="提示" :visible.sync="dialogVisible" width="30%" :before-close="handleClose" lc_id="kl38EP183o"> <el-dialog title="提示" v-model="dialogVisible" width="30%" :before-close="handleClose" lc_id="kl38EP183o">
<span lc_id="o7tyPWHtXQ">这是一段信息</span> <span lc_id="o7tyPWHtXQ">这是一段信息</span>
<span slot="footer" class="dialog-footer" lc_id="4xYQZAAk6B"> <span footer class="dialog-footer" lc_id="4xYQZAAk6B">
<el-button @click="dialogVisible = false" lc_id="nlc9K6Rhcp"> </el-button> <el-button @click="dialogVisible = false" lc_id="nlc9K6Rhcp"> </el-button>
<el-button type="primary" @click="dialogVisible = false" lc_id="mgZZJ553WQ"> </el-button> <el-button type="primary" @click="dialogVisible = false" lc_id="mgZZJ553WQ"> </el-button>
</span> </span>

View File

@ -10,7 +10,7 @@
<el-radio label="btt" lc_id="iP/9XjMVBe">从下往上开</el-radio> <el-radio label="btt" lc_id="iP/9XjMVBe">从下往上开</el-radio>
</el-radio-group> </el-radio-group>
<el-button @click="drawer = true" type="primary" style="margin-left: 16px;" disabled lc_id="hrOAKkng+k">点我打开</el-button> <el-button @click="drawer = true" type="primary" style="margin-left: 16px;" disabled lc_id="hrOAKkng+k">点我打开</el-button>
<el-drawer title="我是标题" :visible.sync="drawer" :direction="direction" :before-close="handleDrawerClose" lc_id="rXvMMLyeYl"> <el-drawer title="我是标题" v-model="drawer" :direction="direction" :before-close="handleDrawerClose" lc_id="rXvMMLyeYl">
<span lc_id="mc44ZyLRo7">我来啦!</span> <span lc_id="mc44ZyLRo7">我来啦!</span>
</el-drawer> </el-drawer>
</div> </div>

View File

@ -13,18 +13,18 @@
</div> </div>
</template> </template>
<script> <script>
import button from "./button"; import button from "./button.vue";
import icon from "./icon";
import layout from "./layout";
import container from "./container";
import form from "./form";
import table from "./table"; import table from "./table";
import formBase from "./form-base"; // import icon from "./icon";
import dialog from "./dialog"; // import layout from "./layout";
import image from "./image"; // import container from "./container";
import final from "./final"; // import form from "./form";
// import formBase from "./form-base";
// import dialog from "./dialog";
// import image from "./image";
// import final from "./final";
import { deepLCEle } from "@/utils/initRawComponent"; // import { deepLCEle } from "@/utils/initRawComponent";
export default { export default {
data() { data() {
@ -34,22 +34,22 @@ export default {
this.$emit('mounted'); this.$emit('mounted');
// lc-mark // lc-mark
let countComponentCount = 0; let countComponentCount = 0;
deepLCEle(document.querySelector('.element-class'), () => { // deepLCEle(document.querySelector('.element-class'), () => {
countComponentCount++; // countComponentCount++;
}); // });
}, },
methods: {}, methods: {},
components: { components: {
"lc-button": button, "lc-button": button,
"lc-icon": icon,
"lc-form": form,
"lc-layout": layout,
"lc-container": container,
"lc-table": table, "lc-table": table,
"lc-form-base": formBase, // "lc-icon": icon,
"lc-dialog": dialog, // "lc-form": form,
"lc-image": image, // "lc-layout": layout,
"lc-final": final, // "lc-container": container,
// "lc-form-base": formBase,
// "lc-dialog": dialog,
// "lc-image": image,
// "lc-final": final,
}, },
}; };
</script> </script>

View File

@ -17,14 +17,6 @@
<span lc_id="m+Oy7pHzNT" lc-mark>Span Element</span> <span lc_id="m+Oy7pHzNT" lc-mark>Span Element</span>
</td> </td>
</tr> </tr>
<tr lc_id="xunAa9pXZZ">
<td lc_id="m11Db3zz1r">
<div class="title" lc_id="dSImHjC62W">center:</div>
</td>
<td lc_id="KrJXHbe0Y4">
<center lc_id="CN8KOU6sKz" lc-mark>Center Element</center>
</td>
</tr>
<tr lc_id="Ejan36KyM/"> <tr lc_id="Ejan36KyM/">
<td lc_id="ke9QDthYso"> <td lc_id="ke9QDthYso">
<div class="title" lc_id="V2t1JzpJnA">a超链接:</div> <div class="title" lc_id="V2t1JzpJnA">a超链接:</div>

View File

@ -1,5 +1,5 @@
import isEqual from "lodash/isEqual"; import isEqual from "lodash-es/isEqual";
import cryptoRandomString from "crypto-random-string"; // import cryptoRandomString from "crypto-random-string";
export function getRawComponentKey(__rawVueInfo__) { export function getRawComponentKey(__rawVueInfo__) {
return Object.keys(__rawVueInfo__)[0]; return Object.keys(__rawVueInfo__)[0];
@ -50,7 +50,7 @@ export function ergodic(jsonObj) {
// 添加ID // 添加ID
if (!jsonObj["lc_id"]) { if (!jsonObj["lc_id"]) {
jsonObj["lc_id"] = cryptoRandomString({ length: 10, type: "base64" }); // jsonObj["lc_id"] = cryptoRandomString({ length: 10, type: "base64" });
} }
} }
} }

View File

@ -1,7 +1,7 @@
import { isObject, isArray, getRawComponentKey } from '@/utils/common'; import { isObject, isArray, getRawComponentKey } from '@/utils/common';
import presetAttribute from "../libs/presetAttribute"; import presetAttribute from "../libs/presetAttribute";
const cryptoRandomString = require("crypto-random-string"); // const cryptoRandomString = require("crypto-random-string");
// 将预生成的ID替换否则当有两个组件挂在同一个树上时后一个会将前一个的属性覆盖 // 将预生成的ID替换否则当有两个组件挂在同一个树上时后一个会将前一个的属性覆盖
export function replaceRowID(codeObj, html) { export function replaceRowID(codeObj, html) {
@ -14,10 +14,7 @@ export function replaceRowID(codeObj, html) {
const element = obj[key]; const element = obj[key];
if (key == "lc_id") { if (key == "lc_id") {
const oldID = obj[key]; const oldID = obj[key];
const newID = cryptoRandomString({ const newID = 3333;
length: 10,
type: "base64",
});
newHtml = newHtml.replace(oldID, newID); newHtml = newHtml.replace(oldID, newID);
obj[key] = newID; obj[key] = newID;
} else if (isObject(element)) { } else if (isObject(element)) {
@ -40,7 +37,7 @@ export function updateLinkTree(codeObj) {
window.tree = {}; window.tree = {};
} }
if (!window.treeWithID) { if (!window.treeWithID) {
const innerObj = {}; let innerObj = {};
Object.defineProperty(window, 'treeWithID', { Object.defineProperty(window, 'treeWithID', {
get: function () { get: function () {
return innerObj; return innerObj;

32
vite.config.js Normal file
View File

@ -0,0 +1,32 @@
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import ViteRequireContext from "@originjs/vite-plugin-require-context";
import path from "path";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
ViteRequireContext(),
],
resolve: {
alias: [
{
find: "@",
replacement: path.resolve(__dirname, "src"),
},
{
find: "vue",
replacement: "vue/dist/vue.esm-bundler.js"
}
],
extensions: [".vue", ".js"],
},
server: {
fs: {
// 可以为项目根目录的上一级提供服务
allow: [".."],
},
},
});

View File

@ -3,7 +3,8 @@ const path = require("path");
module.exports = { module.exports = {
css: { extract: false }, css: { extract: false },
chainWebpack: (config) => { chainWebpack: (config) => {
config.resolve.alias.set("vue$", "vue/dist/vue.esm.js"); // config.resolve.alias.set("vue$", "vue/dist/vue.esm.js");
// config.resolve.alias.set('vue', '@vue/compat/dist/vue.esm-browser.prod.js')
}, },
publicPath: process.env.PUBLIC_PATH, publicPath: process.env.PUBLIC_PATH,