大家好,我是河畔一角,今天给大家介绍一款开源的lowcode插件:rocket-render。我把它定义为火箭引擎,主要基于Vue2+ElementUI封装,使用json快速构建中后台页面。
rocket-render开发背景
前端是一个很有意思的职业,有着UI的既视感:所见即所得;在前端开发领域里面,中后台算是一股清流;做多了以后,基本上千篇一律;它很容易做到复用,又很难做到完全通用。我个人做过很多的后台系统,根据自身的经验结合实战开源了一套rocket-render插件,它不能解决所有问题,它目前也主要是解决简单的重复性问题。其实市面上有很多类似这方面的解决方案了,我呢,只是给大家多一种选择。
rocket-render能解决什么问题
- 开发表单、表格、详情等大量重复代码问题。
- 形成标准化的后台方案,避免参差不齐。
rocket-render提供哪些能力
- 快速开发查询表单,支持多种模式。
- 快速开发常规表格,封装很多快捷功能,支持Element所有表格功能。
- 快速开发复杂表单,支持事件联动、嵌套、自定义等。
- 快速开发详情页面,支持官方所有功能,同时支持快捷功能。
rocket-render提供哪些组件
- SearchForm主要用于查询表单
- RokcetForm主要用于复杂页面表单
- RocketTable主要用于构建表格
- RocketDesc主要用于构建详情页面
rocket-render相关文档
- NPM地址:rocket-render
- Github: rocket-render
- 开发文档:rocket-doc
- 线上预览:rocket-render
rocket-render使用效果预览
- 基本的查询表单
- 拥有丰富的表格功能
- 快速搭建详情页面
rocket-render开发介绍
安装使用
- 安装插件
yarn add rocket-render -S
# 或者
npm install rocket-render -S
复制代码
- 组件注册
// 导入包
import RocketRender from 'rocket-render'
// 导入样式
import 'rocket-render/lib/rocket-render.css'
Vue.use(RocketRender)
复制代码
查询表单介绍
目前支持三种模式的表单:行内表单、栅格表单、flex表单。
- 栅格表单
所谓栅格表单,其实就是栅格布局。根据屏幕分辨率动态控制,1920以上每行4列,1200以上每行3列,1200以下每行2列。
<search-form inline="grid" :json="form" :model.sync="queryForm" @handleQuery="getList"/>
<script>
export default {
data() {
return {
queryForm: {},
form: [
{
type: "input",
model: "user_name",
label: "用户",
placeholder: "请输入用户名称",
},
{
type: "switch",
model: "open",
label: "状态"
}
]
}
},
methods:{
getList(){}
}
};
</script>
复制代码
- Flex表单
flex表单为左右结构,左边依然是行内布局,相比于行内表单,flex只是把查询和重置按钮放到了右边。
<search-form inline="flex" :json="form" :model.sync="queryForm" @handleQuery="getList"/>
<script>
export default {
data() {
return {
queryForm: {},
form: [
{
type: "input",
model: "user_name",
label: "用户",
placeholder: "请输入用户名称",
},
{
type: "switch",
model: "open",
label: "状态"
}
]
}
},
methods:{
getList(){}
}
};
</script>
复制代码
- 行内表单
行内表单表现形式为所有表单控件排成一行,超出自动换行。
<search-form inline="inline" :json="form" :model.sync="queryForm" @handleQuery="getList"/>
<script>
export default {
data() {
return {
queryForm: {},
form: [
{
type: "input",
model: "user_name",
label: "用户",
placeholder: "请输入用户名称",
},
{
type: "switch",
model: "open",
label: "状态"
}
]
}
},
methods:{
getList(){}
}
};
</script>
复制代码
复杂表单介绍
rocket-form主要用来开发复杂表单,支持单列,多列,事件联动等
- 基本用法
一般我们遇到的就是垂直表单,rocket-form支持所有的表单组件,同时支持label、button在表单中的渲染
<rocket-form
ref="rocketForm"
:json="dialogConfig"
v-model="rocketForm"
@handleSubmit="handleSubmit"
@handleClose="handleClose"
></rocket-form>
<script>
export default {
data() {
return {
dialogConfig: {
showFooter: true,//自带footer是否显示
// 布局方式,同element
layout: {
gutter: 15,
},
// 表单列表
formList: [
{
type: 'text',
label: '用户名称',
placeholder: '请输入用户名称',
model: 'cname',
required: true,
width: '80%',
tips: {
align: 'right',
text: '长度最大6位',
},
rules: [
{
required: true,
message: '请输入用户名称',
trigger: ['change', 'blur'],
},
{
pattern: /^[a-zA-Z0-9_\u4e00-\u9fa5]{1,10}$/,
message: '1-10个字符,支持中文、字母、数字和下划线',
trigger: ['change', 'blur'],
},
],
},
{
type: 'select',
label: '用户状态',
placeholder: '请选择用户状态',
model: 'user_status',
tips: '至少选择一项',
options: [
{ label: '已注销', value: 1 },
{ label: '老用户', value: 2 },
{ label: '新用户', value: 3 },
],
},
{
type: 'radio',
label: '使用状态',
placeholder: '请选择使用状态',
model: 'use_status',
options: [
{ label: '在线', value: 1 },
{ label: '离线', value: 2 },
],
},
{
type: 'switch',
label: '启用状态',
model: 'status',
},
{
type: 'date',
label: '注册日期',
model: 'register_date',
shortcuts: true,
},
{
type: 'checkbox',
label: '兴趣',
model: 'intrest',
options: [
{ label: '游泳', value: 1 },
{ label: '打乒乓球', value: 2 },
{ label: '台球', value: 3 },
{ label: '篮球', value: 4 },
],
},
{
type: 'textarea',
label: '用户描述',
placeholder: '请输入用户描述',
model: 'remark',
rows: 4,
},
],
},
// v-model对象,可初始化值
rocketForm: {
cname: 'jack',
intrest: [1, 2],
},
};
},
methods: {
async handleSubmit() {
// 接口提交,大家可以修改为自己的调用方式
const res = await this.$request.get('/user/submit', this.rocketForm);
if (res) {
this.$message.success('操作成功');
// 如果需要,可对表单进行重置
this.$refs['rocketForm'].handleReset();
// 关闭页面
this.handleClose();
}
},
getSelectList(val, values, model) {
this.$request.get('/select/list').then((res) => {
this.dialogConfig.formList[2].list[1].options = res;
});
},
// 关闭弹窗
handleClose() {},
},
};
</script>
复制代码
- 嵌套表单
一行内可以嵌套多个表单
<rocket-form
:json="dialogConfig"
v-model="rocketForm"
@handleSubmit="handleSubmit"
@handleClose="handleClose"
></rocket-form>
<script>
export default {
data() {
return {
dialogConfig: {
showFooter: true,
layout: {
gutter: 15,
},
formList: [
{
type: 'inline',
label: '下拉组合',
list: [
{
type: 'select',
placeholder: '请选择省份',
model: 'user_province',
change: this.getSelectList,
options: [
{
label: '湖北省',
value: 10001,
},
{
label: '上海市',
value: 20001,
},
],
},
{
type: 'select',
placeholder: '请选择城市',
model: 'user_city',
options: [
{
label: '武汉市',
value: 10001,
},
{
label: '上海市',
value: 20001,
},
],
},
],
},
{
type: 'inline',
label: '随意组合',
list: [
{
type: 'radio',
label: '',
placeholder: '请选择使用状态',
model: 'use_status',
options: [
{ label: '在线', value: 1 },
{ label: '离线', value: 2 },
],
},
{
type: 'switch',
label: '启用状态',
model: 'status',
},
],
},
{
type: 'inline',
label: '概率配置',
list: [
{
span: 8,
type: 'select',
placeholder: '请选择概率配置',
model: 'a3',
labelWidth: '0',
options: [
{ label: '10%', value: 1 },
{ label: '20%', value: 2 },
{ label: '30%', value: 3 },
{ label: '40%', value: 4 },
],
},
{
span: 8,
type: 'input',
placeholder: '请输入概率配置',
model: 'a4',
append: '%',
labelWidth: '0',
},
{
span: 3,
type: 'button',
button: {
type: 'text',
text: '按钮',
},
labelWidth: '0',
},
{
span: 5,
type: 'label',
text: '普通文本',
},
],
},
{
type: 'group',
label: '分组 - 组合',
list: [
[
{
span: 8,
type: 'input',
placeholder: '请输入抽取次数',
label: '抽取',
labelWidth: '80px',
model: 'a7',
rules: [
{
required: true,
message: '请输入抽取次数',
trigger: 'blur',
},
],
label1: '次可开启宝箱1',
},
{
span: 8,
type: 'input',
placeholder: '请输入奖励金币',
label: '奖励金币',
model: 'a8',
rules: [
{
required: true,
message: '请输入奖励金币',
trigger: 'blur',
},
],
},
{
span: 3,
type: 'button',
button: {
type: 'primary',
round: true,
icon: 'el-icon-plus',
text: '按钮',
},
click(value, config) {
// 可监听点击事件
console.log(value, config);
},
labelWidth: '0',
},
],
],
},
],
},
// v-model对象,可初始化值
rocketForm: {
cname: 'jack',
intrest: [1, 2],
},
};
},
methods: {
async handleSubmit() { },
getSelectList(val, values, model) { },
handleClose() { }
},
};
</script>
复制代码
表格介绍
rocket-table支持el-table的所有功能,属性和事件均透传,同时添加很多方便使用的快捷功能
支持功能如下:
- 基础表格
- 表格分页(可控制隐藏,默认显示)
- 工具条(刷新、表格密度、列设置、全屏)
- 单列可点击、多列可点击
- 多个链接(link)渲染、图片渲染、url渲染、badge状态渲染
- 特殊数据格式化(formatter)
- 操作区域权限控制(创建、编辑、删除)
- 表格列排序、表头跨列、数据跨行
- 通过v-bind=" listners"保留大部分原生属性和事件
- 支持表格索引列、支持表格多选功能
- 支持表格自定义列
基本用法
<search-form :json="form" :model.sync="queryForm" @handleQuery="getTableList" />
<rocket-table
:column.sync="columns"
:data="list"
:pagination.sync="pagination"
@handleChange="getTableList"
@handleAction="handleAction"
>
<template v-slot:title>用户列表</template>
</rocket-table>
<script>
export default {
data () {
return {
// 保存查询条件
queryForm: {},
form: [
{
type: 'text',
model: 'user_name',
label: '用户',
placeholder: '请输入用户名称',
}
],
columns: [
{
prop: 'selection',
type: 'selection',
label: '选框',
},
{
prop: 'uid',
label: '用户ID',
align: 'left',
type: 'click'
},
{
prop: 'user_img',
label: '头像',
type: 'image',
image: {
type: 'single'
}
},
{
prop: 'use_status',
label: '当前状态',
formatter (row) {
return {
1: '在线',
2: '离线',
}[row.use_status]
},
},
{
prop: 'user_status_name',
label: '用户状态',
type:'badge',
badge:{
id: "user_status",//渲染的字段
state: {
1: "warning",//设置颜色
2: "primary",
3: "danger",
4: "info"
},
}
},
{
prop: 'register_date',
label: '注册时间',
}
],
list: [],
// 分页对象,目前为固定结构
pagination: {
pageNum: 1,
pageSize: 20,
total: 0,
}
}
},
mounted () {
this.getTableList()
},
methods: {
// 首页列表查询,page为子组件传递的页码,默认为1
getTableList (pageNum = 1) {
this.pagination.pageNum = pageNum
const data = {
...this.queryForm, // 查询表单数据
...this.pagination, // 默认分页数据
}
this.$request.get('/basic/list',data).then((res) => {
this.list = res.list.slice(0,5)
this.pagination.total = res.total
})
}
}
}
</script>
复制代码
列点击、操作按钮列,图片渲染
支持单元格点击、操作按钮列、图片、链接渲染,简单的属性配置即可实现复杂的功能
<rocket-table
:column.sync="columns"
:data="list"
:pagination.sync="pagination"
@handleChange="getTableList"
@handleAction="handleAction"
@handleCellClick="handleCellClick"
@selection-change="handleSelectionChange"
>
<template v-slot:title>用户列表</template>
<template v-slot:action>
<el-button type="primary" @click="showModal1 = true"
>操作按钮</el-button
>
</template>
</rocket-table>
<script>
export default {
data () {
return {
columns: [
{
prop: 'selection',
type: 'selection',
label: '选框',
},
{
prop: 'uid',
label: '用户ID',
align: 'left',
type: 'click'
},
{
prop: 'user_img',
label: '头像',
type: 'image',
image: {
type: 'single'
}
}
],
list: [],
// 分页对象
pagination: {
pageNum: 1,
pageSize: 20,
total: 0,
}
}
},
mounted () {
this.getTableList()
},
methods: {
// 首页列表查询,page为子组件传递的页码,默认为1
getTableList (pageNum = 1) {
this.pagination.pageNum = pageNum
const data = {
...this.queryForm, // 查询表单数据
...this.pagination, // 默认分页数据
}
this.$request.get('/basic/list',data).then((res) => {
this.list = res.list.slice(0,5)
this.pagination.total = res.total
})
},
// 操作项点击,根据按钮索引开发不同业务逻辑
handleAction({ index, row, type }){
if(index === 0){
// 点击了第一个操作按钮
}else if(index === 1){
// 点击了第二个操作按钮
}
// 也可根据type进行列判断,代替索引
if(type === 'user_state'){
// 点击了用户状态按钮
}
},
/**
* 列点击
* 1. 只有其中一列可点击,通常只用row就够了,不需要根据prop做判断
* 2. 有多列可点击,根据prop判断是哪一列被触发了
* 3. 某一列有多个点击按钮,点击按钮的时候,会把对应的值回传回来(link)
*/
handleCellClick({ row, prop, link }){
// 如果是多个列都绑定了click事件,可根据prop来区分是哪一列
if(prop === 'uid'){
this.$message.success('点击了用户ID')
}
},
// 列多选
handleSelectionChange (rows) {
this.$message.success('勾选项id为' + rows.map(item => item.id))
}
},
}
</script>
复制代码
跨行用法
支持列自定义、跨行跨列
<rocket-table
:column.sync="columns"
:data="list"
>
</rocket-table>
<script>
export default {
data(){
return {
columns:[
{
prop: 'user_info',
label: '用户信息',
align: 'center',
span: [ // 多级表头
{
prop: "cname",
label: "用户名称",// 普通列渲染
showOverflowTooltip:true // true/false/不填,默认为true
},
{
prop: "intrest_name",
label: "兴趣",
width: 70,// 可调整列宽度
},
]
},
{
prop: "uid",
label: "用户ID",
type: 'label'
}
],
list:[],// 表格渲染数据
pagination:{ page:1 }
}
},
mounted () {
this.getTableList()
},
methods: {
// 首页列表查询,page为子组件传递的页码,默认为1
getTableList (page = 1) {
this.pagination.page = page
const data = {
...this.queryForm, // 查询表单数据
...this.pagination, // 默认分页数据
}
this.$request.get('/basic/list',data).then((res) => {
this.list = res.list.slice(0,5)
})
}
}
}
</script>
复制代码
详情组件介绍
详情页面也是中后台经常使用的一个功能,如果用原生开发,要复制太多的标签组件,使用json开发反而最容易,整个用法同el-descriptions
基本用法 - 不带边框
<rocket-desc :json="json1" :values="values1" />
<script>
export default {
data() {
return {
json1: {
title: '基础描述-1',
list: [
{
label: '用户名称',
prop: 'userName',
},
{
label: '用户性别',
prop: 'userSex',
},
{
label: '用户年龄',
prop: 'userName',
},
{
label: '用户职业',
prop: 'userJob',
},
{
label: '用户年薪',
prop: 'userSalary',
},
],
},
values1: {
userName: '杰克',
userAge: 30,
userSex: '未知',
userJob: '前端工程师',
userSalary: '20万',
},
};
},
};
</script>
复制代码
基本用法 - 带边框,每行 2 列
<rocket-desc :json="json2" :values="values2" />
<script>
export default {
data() {
return {
json2: {
title: '基础描述-2',
border: true,
column: 2,
list: [
{
label: '用户名称',
prop: 'userName',
},
{
label: '用户性别',
prop: 'userSex',
},
{
label: '用户年龄',
prop: 'userName',
},
{
label: '用户职业',
prop: 'userJob',
},
{
label: '用户年薪',
prop: 'userSalary',
},
],
},
values2: {
userName: '杰克',
userAge: 30,
userSex: '未知',
userJob: '前端工程师',
userSalary: '20万',
},
};
},
};
</script>
复制代码
基本用法 - 垂直分布
<rocket-desc :json="json3" :values="values3" />
<script>
export default {
data() {
return {
json3: {
title: '基础描述-3',
border: true,
column: 4,
direction: 'vertical',
extra: '看我',
list: [
{
label: '用户名称',
prop: 'userName',
},
{
label: '用户性别',
prop: 'userSex',
formatter({ userSex }) {
return userSex == '未知' ? '泰国人妖' : userSex;
},
},
{
label: '用户年龄',
prop: 'userName',
},
{
label: '用户职业',
prop: 'userJob',
},
{
label: '用户年薪',
prop: 'userSalary',
},
{
label: '用户地址',
prop: 'address',
},
],
},
values3: {
userName: '杰克',
userAge: 30,
userSex: '未知',
userJob: '前端工程师',
userSalary: '20万',
address: '上海市浦东新区东方明珠',
},
};
},
};
</script>
复制代码
基本用法 - 弹框中显示
<el-button @click="showVisible = true" type="primary"> 弹框中显示 </el-button>
<el-dialog
title="弹框描述"
:visible.sync="showVisible"
width="40%"
:before-close="handleClose"
>
<rocket-desc :json="json2" :values="values" class="mt20" />
<rocket-desc :json="json4" :values="values" class="mt20" />
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="handleClose">确定</el-button>
</span>
</el-dialog>
<rocket-desc :json="json3" :values="values3" />
<script>
export default {
data() {
return {
showVisible: false,
json2: {
title: '基础描述-2',
border: true,
column: 2,
list: [
{
label: '用户名称',
prop: 'userName',
},
{
label: '用户性别',
prop: 'userSex',
},
{
label: '用户年龄',
prop: 'userName',
},
{
label: '用户职业',
prop: 'userJob',
},
{
label: '用户年薪',
prop: 'userSalary',
},
{
label: '用户地址',
prop: 'address',
},
],
},
json4: {
title: '基础描述-4',
border: true,
column: 1,
list: [
{
label: '用户名称',
prop: 'userName',
},
{
label: '用户性别',
prop: 'userSex',
},
{
label: '用户年龄',
prop: 'userName',
},
{
label: '用户职业',
prop: 'userJob',
},
{
label: '用户年薪',
prop: 'userSalary',
},
{
label: '用户地址',
prop: 'address',
},
],
},
values: {
userName: '杰克',
userAge: 30,
userSex: '未知',
userJob: '前端工程师',
userSalary: '20万',
address: '上海市浦东新区东方明珠',
},
};
},
methods: {
handleClose() {
this.showVisible = false;
},
},
};
</script>
复制代码
基本用法 - 自定义标题、label 和 value
<rocket-desc :json="json2" :values="values" class="mt20">
<template slot="title">
<el-button type="primary" size="small">自定义标题</el-button>
</template>
<template slot="extra">
<el-button type="primary" size="small">右上角自定义</el-button>
</template>
<template slot="userName">
<i class="el-icon-user"></i>
{{ values.userName }}
</template>
<template slot="userSex">
<el-tag>{{ values.userSex }}</el-tag>
</template>
</rocket-desc>
<el-tabs v-model="activeType" class="mt20">
<el-tab-pane label="注册信息" name="1">
<rocket-desc :json="json4" :values="values" />
</el-tab-pane>
<el-tab-pane label="认证信息" name="2">
<rocket-desc :json="json4" :values="values" />
</el-tab-pane>
<el-tab-pane label="补充信息" name="3">
<rocket-desc :json="json4" :values="values" />
</el-tab-pane>
</el-tabs>
<script>
export default {
data() {
return {
activeType: '1',
showVisible: false,
json2: {
title: '标题自定义插槽',
border: true,
type: 'slot',
list: [
{
label: '用户名称',
prop: 'userName',
type: 'slot',
slotLabelName: 'userName',
},
{
label: '用户性别',
prop: 'userSex',
type: 'slot',
slotValueName: 'userSex',
},
{
label: '用户年龄',
prop: 'userName',
},
{
label: '用户职业',
prop: 'userJob',
},
{
label: '用户年薪',
prop: 'userSalary',
},
{
label: '用户地址',
prop: 'address',
},
],
},
json4: {
border: true,
list: [
{
label: '用户名称',
prop: 'userName',
},
{
label: '用户性别',
prop: 'userSex',
},
{
label: '用户年龄',
prop: 'userName',
},
{
label: '用户职业',
prop: 'userJob',
},
{
label: '用户年薪',
prop: 'userSalary',
},
{
label: '用户地址',
prop: 'address',
},
],
},
values: {
userName: '杰克',
userAge: 30,
userSex: '未知',
userJob: '前端工程师',
userSalary: '20万',
address: '上海市浦东新区东方明珠',
},
};
},
methods: {
handleClose() {
this.showVisible = false;
},
},
};
</script>
复制代码
rocket-desc组件使用起来跟表格类似,支持formatter格式化。
以上就是整个rocket-render的介绍,如果大家有中后台的系统开发需求,我相信rocket-render一定能够帮到你,如果系统有不合理的地方,也欢迎大家指正。