扫盲低代码-vue3实现低代码平台
低代码盛行多年了,刚好公司最近有项目需要做这块,从萌新小白,到实现程序,一步一步踩过了很多坑,今天就把我踩过的坑一一分享出来,带你扫盲如何实现低代码,今天我们就从0开始,使用vue+pinia实战低代码!
希望通过我的分享,你能收获到低代码是如何实现,工作的等一系列的问题,话不多说,直接上干货!
项目初始化
直接执行以下脚手架命令,生成一个新的项目模板,如有疑问可参考官网cn.vuejs.org/guide/quick…
npm init vue@latest
执行命令,一路选No,在✔ Add Pinia for state management? … No / Yes此条命令时,选择yes,如此项选择了no,后面需自己手动在安装下pinia。
进入项目目录执行
npm install
npm run dev
此时如果你的项目没有问题,会打开一个本地服务,端口为5173,我们在浏览器直接输入localhost:5173,会打开一个页面,如下图,标志着你已经开启了一段新的旅程!
ok,我们删除一些不必要的默认文件保持整个项目的整洁,我们把components下所有组件都删除,把app.vue文件整理成如下:
<script setup></script>
<template>
<div>起航吧,少年郎!</div>
</template>
<style scoped>
body {
margin: 0;
padding: 0;
}
</style>
此时查看浏览器你的页面应该变成了一句话,起航吧少年郎!!!
下面我们安装一些必要的npm包,首先我们安装css预处理器 sass和sass-loader,然后我们安装vue-draggable-next(ps:vue3兼容包,老包不兼容vue3),用来处理我们拖曳操作,好的让我们执行
npm install --save sass sass-loader vue-draggable-next
,安装完成后,我们在app.vue文件中将样式部分修改为:
<style scoped lang="scss">
body {
margin: 0;
padding: 0;
}
</style>
查看页面没有报错,文字正常显示。
项目实现
这部分主要是一步一步的去实现项目
1:实现布局
首先我们在页面完成,页面布局,这部分大家自由去做就行了,做完以后大概就是这个样式
上部分是个页面头部,左侧放我们的组件,右侧放组件的设置属性,中间部分是渲染区。
我们安装一下element-plus和vue-router,后面我们实现预览和开发组件的时候会用到。
直接按照配置进行就可以:
element-ui官网
vue-router官网
2:实现数据定义和拖曳区,渲染区
下面我们实现两个组件,这里我用比较简单的组件来实现操作,后续业务的话可以根据实际去调整! 首先我们在store文件中定义如下json,这里是我们的数据中心,我们所有的组件渲染,页面渲染都需要使用数据去完成
import { defineStore } from "pinia";
export const useLowCodeStore = defineStore({
id: "lowcode", // id必填,且需要唯一
state: () => {
return {
component: [
{
code: "button",
set: "button-set",
name: "按钮",
id: 1, //组件编号不可重复且递增
props: {
type: "primary",
},
},
{
code: "input",
set: "input-set",
name: "输入框",
id: 2, //组件编号不可重复且递增
props: {
value: "",
placeholder: "请输入内容",
},
},
],
preview: {},
nowComponent: {},
};
},
actions: {},
});
回到主页面,调用数据,渲染出对应的组件,并且实现拖曳,我们这里借用了vue-drag-next包帮助我们去做拖曳的事件操作。
下面我们完成可拖曳区代码: 可拖曳实现:
<VueDraggableNext
v-model="store.component"
:sort="false"
:group="{
name: 'components', //组名为icomponents
pull: 'clone', //是否允许拖出当前组
put: false, //是否允许拖入当前组
}"
>
<div v-for="item in store.component" :key="item.id" class="tem_btn">
{{ item.name }}
</div>
</VueDraggableNext>
渲染区实现
<VueDraggableNext
:v-model="store.preview"
:group="{
name: 'template',
pull: false,
put: true,
}"
ghost-class="ghost"
class="canvas"
>
<template v-for="item in store.preview" :key="item.id">
<component
:is="componentsList[item?.code]"
:data="item"
></component>
</template>
</VueDraggableNext>
好了到这里我们基本完成了主要的功能,如果你没有出现错误,那么页面应该是下面这个样子
接下来让我们去实现两个简单的组件
3:实现组件及属性设置
1:先来写个简单的button组件
在components文件夹下新建button文件,在button文件夹下面新建index.vue文件,这个文件是我们的组件,然后新建set.vue文件,这个文件是我们组件属性设置的文件。
我们先来分析下我们定义的数据,button组件接收了两个数据,一个type,用来渲染样式,一个value用来渲染值,我们根据这两个属性去写我们的组件,其代码如下:
// 组件代码
<template>
<el-button :type="props.data.props.type">{{
props.data.props.value
}}</el-button>
</template>
<script setup>
import { watch } from "vue";
const props = defineProps({
data: Object,
});
</script>
// 属性设置代码
<template>
<el-button @click="() => set('primary')">默认</el-button>
<el-button @click="() => set('success')">成功</el-button>
</template>
<script setup>
import { useLowCodeStore } from "../../store/lowcode";
const store = useLowCodeStore();
const set = (str) => {
const value = store.nowComponent;
value.props.type = str;
store.updateNowComponents(value);
};
</script>
然后实现input组件
<template>
<el-input
:value="props.data.props.value"
:placeholder="props.data.props.placeholder"
></el-input>
</template>
<script setup>
import { watch } from "vue";
const props = defineProps({
data: Object,
});
</script>
// 属性设置代码
<template>
设置value
<el-input v-model="valueData"></el-input>
设置placeholder
<el-input v-model="valueData2"></el-input>
<el-button @click="() => set()">确认</el-button>
</template>
<script setup>
import { ref } from "vue";
import { useLowCodeStore } from "../../store/lowcode";
const store = useLowCodeStore();
const valueData = ref("");
const valueData2 = ref("");
const set = (str) => {
const value = store.nowComponent;
value.props.value = valueData.value;
value.props.placeholder = valueData2.value;
store.updateNowComponents(value);
};
</script>
4:实现拖曳渲染
到这里我们基本易经完成了所有的开发工作,下面让我们把流程串起来就可以实现我们的低代码操作了 首先在store中添加如下代码,用来实现我们的业务逻辑
actions: {
previewData(value) {
this.preview.push(value);
},
nowComponentsData(value) {
this.nowComponent = value;
},
updateNowComponents(value) {
this.nowComponent = value;
const index = this.preview.findIndex((item) => item.id === value.id);
this.preview[index] = value;
},
},
在app.vue中添加拖曳事件和引入我们的组件,我这里直接给出完整的代码
<template>
<div class="low_box">
<div class="header">
<div class="title">可视化系统</div>
<div class="web">pc</div>
<div class="btn">
<el-button type="primary">预览</el-button
><el-button type="primary">确定</el-button>
</div>
</div>
<div class="content">
<div class="left">
<div class="title">组件</div>
<VueDraggableNext
v-model="store.component"
:sort="false"
:group="{
name: 'components', //组名为icomponents
pull: 'clone', //是否允许拖出当前组
put: false, //是否允许拖入当前组
}"
@end="onEnd"
>
<div v-for="item in store.component" :key="item.id" class="tem_btn">
{{ item.name }}
</div>
</VueDraggableNext>
</div>
<div ref="targetContent" class="center">
<VueDraggableNext
:v-model="store.preview"
:group="{
name: 'template',
pull: false,
put: true,
}"
ghost-class="ghost"
class="canvas"
>
<template v-for="item in store.preview" :key="item.id">
<component
:is="componentsList[item?.code]"
:data="item"
></component>
</template>
</VueDraggableNext>
</div>
<div class="right">
<component :is="componentsList[store?.nowComponent?.set]"></component>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { shallowRef, ref, onBeforeMount, watch } from "vue";
import { VueDraggableNext } from "vue-draggable-next";
import { useLowCodeStore } from "./store/lowcode";
import Button from "./components/Button/index.vue";
import Input from "./components/Input/index.vue";
import ButtonSet from "./components/Button/set.vue";
import InputSet from "./components/Input/set.vue";
const store = useLowCodeStore();
watch(store, (n, l) => {
console.log("数据", n);
});
const componentsList = {
button: Button,
input: Input,
"button-set": ButtonSet,
"input-set": InputSet,
};
const onEnd = (obj: any) => {
const { oldDraggableIndex } = obj;
store.previewData(store.component[oldDraggableIndex]);
store.nowComponentsData(store.component[oldDraggableIndex]);
};
</script>
<style lang="scss" scoped>
.low_box {
width: 100%;
height: 100%;
overflow: hidden;
background-color: #f2f2f2;
.header {
height: 65px;
background-color: #fff;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 0 20px;
}
.content {
display: flex;
flex-direction: row;
height: calc(100vh - 66px);
.left {
width: 300px;
height: 100%;
overflow: hidden;
background-color: #fff;
border-top: 1px solid #dddddd;
.title {
font-size: 16px;
color: #333;
line-height: 50px;
width: calc(100% - 40px);
margin-left: 20px;
border-bottom: 1px solid #f2f2f2;
clear: both;
}
.tem_btn {
padding: 0px 10px;
height: 30px;
line-height: 30px;
text-align: center;
font-size: 14px;
color: #666;
background-color: #f2f2f2;
border-radius: 4px;
cursor: move;
user-select: none;
margin-top: 20px;
float: left;
margin-left: 20px;
}
}
.center {
flex: 1;
padding: 20px;
background-color: #f2f2f2;
.canvas {
background-color: #fff;
width: 100%;
height: 100%;
}
.ghost {
background-color: #f00 !important;
}
}
.right {
width: 300px;
height: 100%;
overflow: hidden;
background-color: #fff;
border-top: 1px solid #dddddd;
}
}
}
</style>
好了,到这里已经完成实现了我们的拖曳操作,渲染,以及属性设置,如果没有错误结果应该如下图
页面实现
好了上面我们已经实现了低代码操作,那么我们生成的数据,怎么供给到别的项目消费呢?我这里使用多页面的方式去处理的这个问题,这种方式比较简单,能解决90%的业务了吧!
首先在根目录下新建preview文件夹,拷贝一份页面到preview中,修改vite.config.js的配置,增加多页面配置项目:
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import * as path from "path";
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
plugins: [vue()],
build: {
cssCodeSplit: true, // 如果设置为false,整个项目中的所有 CSS 将被提取到一个 CSS 文件中
sourcemap: false, // 构建后是否生成 source map 文件。如果为 true,将会创建一个独立的 source map 文件
target: "modules", // 设置最终构建的浏览器兼容目标。默认值是一个 Vite 特有的值——'modules' 还可设置为 'es2015' 'es2016'等
chunkSizeWarningLimit: 550, // 单位kb 打包后文件大小警告的限制 (文件大于此此值会出现警告)
assetsInlineLimit: 4096, // 单位字节(1024等于1kb) 小于此阈值的导入或引用资源将内联为 base64 编码,以避免额外的 http 请求。设置为 0 可以完全禁用此项。
minify: "terser", // 'terser' 相对较慢,但大多数情况下构建后的文件体积更小。'esbuild' 最小化混淆更快但构建后的文件相对更大。
terserOptions: {
compress: {
drop_console: true, // 生产环境去除console
drop_debugger: true, // 生产环境去除debugger
},
},
rollupOptions: {
input: {
main: path.resolve(__dirname, "index.html"),
preview: path.resolve(__dirname, "preview/index.html"),
},
},
},
optimizeDeps: {
include: [
"@vueuse/core",
"element-plus",
"vant",
"lodash-es",
"vuedraggable",
],
},
});
此时我们点击确定按钮会打开一个新页面,就是我们渲染出来的页面,这里我们可以使用iframe的方式引入页面,只需要于后端沟通好数据存储,就可以渲染出我们任意拖曳生成的页面。
到这里基本分享完了低代码的思路,我这里也是刚好最近公司需要做一个活动生成系统的项目,专门去看了下,根据自己的经验去实现了需求,可能还有更好的方式,这里抛转引玉了!!!
你那么帅,那么美,留个赞再走吧!
转载自:https://juejin.cn/post/7211420858212925500