背景
我们都知道,业务数据可以通过后台API进行提交或者展示的,那么前端代码是否也可以通过后台API返回的方式进行动态的展示呢?
我们先来看看,后台给我们返回的是什么?后台返回给我们的无非就是对象或者数组,那么我们将表单的formItem,都写成数组模式呢?
简单的例子
我们以一个简单的表单为例子
这是Vue的模板写法
<template>
<div class="">
<el-row>
<el-col :span="5" :offset="10">
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="姓名">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="性别">
<el-select v-model="form.region" placeholder="性别">
<el-option label="男" value="1"></el-option>
<el-option label="女" value="2"></el-option>
</el-select>
</el-form-item>
<el-form-item label="店时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="form.date1" style="width: 100%;"></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker placeholder="选择时间" v-model="form.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item label="是否会员">
<el-switch v-model="form.delivery"></el-switch>
</el-form-item>
<el-form-item label="意向商品">
<el-checkbox-group v-model="form.type">
<el-checkbox label="美食" name="type"></el-checkbox>
<el-checkbox label="家具" name="type"></el-checkbox>
<el-checkbox label="玩具" name="type"></el-checkbox>
<el-checkbox label="美妆" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="备注">
<el-input type="textarea" v-model="form.desc"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" >保存</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
data() {
return {
form: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
}
}
},
created(){
},
methods: {
}
}
</script>
在这个表单中,每一个输入内容均由一个el-form-item包裹起来,我们可以尝试通过for循环将代码渲染。
将前端代码放到data中,用数组装起来,通过v-for进行渲染:
<el-form-item :key="item.itemId" v-for="item in formItemList" :label="item.label">
<component
:is="item.component"
:codeFiled="item.code"
:type="item.type"
:proOptionData="item.proOptionData"
:code="form[item.code]"
@changeCode="getCode"
/>
</el-form-item>
formItemList:[
{
itemId:'itemId1',
label:'姓名',
code:'name',
component:() => import('@/components/input')
},
{
itemId:'itemId2',
label:'性别',
code:'region',
component:() => import('@/components/select'),
proOptionData:[
{
value:'1',
label:'男'
},
{
value:'2',
label:'女'
},
]
},
{
itemId:'itemId3',
label:'入店日期',
code:'date1',
component:() => import('@/components/datePicker'),
},
{
itemId:'itemId4',
label:'是否会员',
code:'delivery',
component:() => import('@/components/switch')
},
{
itemId:'itemId5',
label:'意向商品',
code:'type',
component:() => import('@/components/checkBoxGroup'),
proOptionData:[
{
value:'1',
label:'美食'
},
{
value:'2',
label:'家具'
},
{
value:'4',
label:'玩具'
},
{
value:'5',
label:'美妆'
},
]
},
{
itemId:'itemId6',
label:'备注',
type:'textarea',
code:'desc',
component:() => import('@/components/input')
},
],
src的代码路径结构
这样就能在数组中控制页面渲染的表单的多少了,但是我们可以发现,引入子组件的component是一个函数,它无法保存在数据中,所以我们需要把它改成字符串的形式。
formItemList: this.publicMethod.getFormItem([
{
itemId:'itemId1',
label:'姓名',
code:'name',
component:'@/components/input'
},
{
itemId:'itemId2',
label:'性别',
code:'region',
component:'@/components/select',
proOptionData:[
{
value:'1',
label:'男'
},
{
value:'2',
label:'女'
},
]
},
{
itemId:'itemId3',
label:'入店日期',
code:'date1',
component:'@/components/datePicker',
},
{
itemId:'itemId4',
label:'是否会员',
code:'delivery',
component:'@/components/switch'
},
{
itemId:'itemId5',
label:'意向商品',
code:'type',
component:'@/components/checkBoxGroup',
proOptionData:[
{
value:'1',
label:'美食'
},
{
value:'2',
label:'家具'
},
{
value:'4',
label:'玩具'
},
{
value:'5',
label:'美妆'
},
]
},
{
itemId:'itemId6',
label:'备注',
type:'textarea',
code:'desc',
component:'@/components/input'
},
]),
编写一个构建component的公共函数:
export function getFormItem(formItemArr){
let arr = formItemArr
if(arr.length>0){
for(let item of arr){
let component = item.component.split('components/')[1]
item['component'] = () => import(`@/components/${component}`)
}
}else{
arr = []
return []
}
return arr
}
在main.js中绑定到Vue原型上:
import * as publicMethod from './publicMethod/index'
Vue.prototype.publicMethod = publicMethod //全局注册,公共方法
通过配置化编写前端代码的方法已经基本完成,接下来需要通过后台API来引入formItemList,先构建后台数据库:
组件的数据表:
下拉框数据表:
后台代码:(T.T不是专业的后台,忽喷,努力改进中)
var express = require('express');
var router = express.Router();
var mysql = require('mysql');
//把数据库的密码,账号,地址,端口,表格都连接上!!
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'Yang1198432033.',
port: '3306',
database: 'peizhihua'//上文说的名字
});
connection.connect();
//查,数据库代码
var sql = 'SELECT * FROM itemlist WHERE view=?';
let sql1 = 'SELECT * FROM prooptiondata WHERE proOptionDataId=?'
async function connect(sql,req){
let res = await connection.query(sql,req)
}
/* GET home page. */
router.post('/api', function(req, res, next) {
let query = req.body
let list = []
connection.query(sql,query.view, function (err, queryRes) { //询问访问数据库,也就是去嫩那个数据库
if (err) { //失败就报个错。
return;
}
list = JSON.parse(JSON.stringify(queryRes));
let length = list.filter((i)=> i.proOptionData == 1)
length = length.length
let index = 0
for(let i in list){
if(list[i].proOptionData){
connection.query(sql1,list[i].proOptionDataId, function (err, queryRes) { //询问访问数据库,也就是去嫩那个数据库
if (err) { //失败就报个错。
return;
}
let arr = JSON.parse(JSON.stringify(queryRes));
list[i].proOptionData = arr
index+=1
if(index == length){
res.writeHead(200, {
'content-type': 'text/html;charset=utf8'
});
res.end(JSON.stringify({result:'1',list:list}));
}
})
}
}
});
});
module.exports = router;
在created中访问API:
created(){
const that = this
this.$axios({
method: 'post',
url: '/api',
data: {view:'form'}
}).then((res)=>{
that.formItemList = this.publicMethod.getFormItem(res.data.list)
}).catch((err) =>{
that.formItemList = this.publicMethod.getFormItem(that.stateFormItemList)
//静态数组
})
},
大功告成:
配置化写法可以设置一个控制台,根据用户需求增加、修改和删除具有相同特性的元素,比如表单、按钮、表格的列等,后续还可以用缓存的机制,以便不用每次进入页面都需要访问一次API。