Closed Leedorado closed 5 years ago
用json其实是一种约束,不直接调用组件,而是通过 json 声明我要什么功能,具体实现不用管!这其实能降低使用者的门槛和成本,不太擅长前端的开发人员也可以用(比如 RD)。这其实就是一种声明式编程的好处。
用户不直接接触组件这一层,而只关心 json 配置的好处是,内部发生技术变更对于用户是无感知的,不会因为升级还要改变写法。
其实在公司内部,还有可视化编辑器,还有平台,在平台上可以直接创建编辑页面。
后期会开源可视化编辑器吗?
应该不会,但是可以提供可视化工具(非源码版本)。
AMIS 渲染器本质就是把代码中大量重复的 state-to-view mapping 做了一层抽象,并且赋予开发者基于这个规范的抽象的能力。你想用插件也是没有门槛的,AMIS 所有的渲染器都是通过 FormItem 装饰器创建的,你想订制只要给你的组件封装一下即可,你自己订制的渲染器就算是产品经理也可以通过配置 JSON 来生成,说没有减少代码工作量是不可能的。
有学习参考价值。本人原先业余也搞过类似的工具 ngx-form-builder,用的是ng。一样是通过 jsonschema
来动态创建组件,也是想后期做可视化编辑器,最终也是走回jsonschema——>component
的过程。
感谢开源。
@2betop @Leedorado QCon期间很遗憾没听到这次分享,去听头条的消息队列分享去了。
先说结论:
假设前端需要写一个页面,提交用户名、邮箱、部门信息至后台,通常我们可能这样来做:
这时你的代码可能长这样子:
<script>
export default {
data(){
return{
email:'',
username:'',
department:[]
}
},
methods: {
async init(){
let data = await db.fetchDepartment();
this.department=data;
}
},
mounted() {
this.init()
},
}
</script>
或者这样子:
import React,{useState,useEffect} from 'react'
export default function YourComponent(){
let [state,setState] = useState({
email:'',
username:'',
department:[]
});
useEffect(async ()=>{
let department = await db.fetchDepartment();
setState({department});
})
// ...
}
根据上面的数据,结合选用的UI库写好UI层,这时可能需要写好字段的说明如邮箱、姓名、部门,input框还需要placeholder,而邮箱字段可能还需要做数据校验,同时做好数据绑定和事件绑定。
这时一般都会有个【提交】以及【重置】按钮,如果需要数据更新,可能还有个【更新】按钮。
通常需要在提交按钮绑定 submit 事件,里面的流程大致是: 数据校验 ——> 拼接参数——> 发送至后台——> 成功/失败后的响应。
说明:在以上的操作中,像selector中部门数据的初始化,UI层中的placeholder,必要的提示信息等都可以做成配置绑定在初始化的state中。
在写了很多个相似的业务页面以后,我们其实可以将很多工作抽象出来,这就是AMIS所做的工作。 比如一个 文本输入框可能是这样的:
{
"title": "用户名",
"type": "input",
"key": "username", // 这里的key一是用在数组到视图的过程中,虚拟DOM需要传入的key,同时作为数据提交接口的入参字段
"rule": {
"required": true,
"msg": "请输入有效用户名"
},
"placeholder": "请输入用户名",
"maxLength": 8,
"toupper": "true"
}
当发现这样可行以后,逐步添加各种封装组件,根据各个组件的特性设置对应的个性化属性,比如
开关Switch ...... 等,对于有初始数据的组件,可以同时考虑配置一个api初始化接口,在视图初始化之前加载数据,此时的初始化配置可能是这样的:
{
"title": "单选部门",
"type": "select",
"url": "27/9b520a55df.json", // 载入表单JSON后,对于select这种需要初始数据的组件,通过url参数初始化数据,将结果传入组件
"key": "dept_id4",
"rule": {
"required": true
},
"cascade": "dept_id",// 当dept_id字段数据更新后(如对应的select下拉选择触发),重新init当前组件的数据
"block": "当dept_id变更时,加载该组件数据" // 一些必要的提示信息
}
对下拉框,我们还可以考虑再次封装,加入拼音首字母过滤、是否支持复选、级联选择等功能。
通过以上配置能渲染出单个组件后,还需要整体考虑,比如表单的名称、CRUD接口等,这时整个表单的配置可能像下面这样:
{
"name": "业务表单名称",
"api": {
"insert": {
"url": "81/7e63360284",
"param": ["rec_time", "uid"],
"_desc": "insert into tbl_sample_bar(data_type,data_value,data_count ) values (?,?,?)"
},
"update": {
"url": "83/ae9b8e8b0f",
"param": ["_id"],
"_desc": "update tbl_sample_bar set data_type = ?,data_value = ?,data_count = ? where id=?"
},
"delete": {
"url": "84/dac2a713d0",
"param": ["_id"],
"_desc": "delete from tbl_sample_bar where id=?"
},
"query": {
"url": "82/ef0905c692?param1=2",
"param": ["data_type", "data_value"],
"_desc": "SELECT id _id,a.data_type,a.data_value,a.data_count FROM tbl_sample_bar AS a where a.data_type=? and a.data_value=? order by id desc"
}
},
"detail": [
// 页面视图的各个录入组件的配置
]
}
根据JSON中的初始配置,根据我们在传统的MVVM开发流程中调用配置中的CRUD接口做对应的功能实现。
对于需要额外实现的功能,可以根据业务情况不断丰富配置并实现,最终达到只设置json文件便可满足各类表单的业务需求。
系统URL可能是 http://localhost/form#schema=某业务.json 监听schema的变更,载入对应的 json文件即可。
将URL 【http://localhost/form#schema=某业务.json】 添加至菜单中,这时一个配置式的表单功能页面就完成了
最后抛砖引玉,本人在前段时间也基于 Antd 做过类似的工作,有了基本功能但没AMIS这么完整,比如没加入表单的横向或纵向排列设置、基于table的crud操作、分步骤的表单填写、弹出dialog创建子表单等:
https://github.com/realeve/sheet_manager/blob/master/src/components/FormCreater/index.tsx
好处就是让某些特定领域的业务需求通过拖拽,简单配置,让可视化编程成为可能。json是桥梁
简单的说可以把它理解为一种协议啦
我们也在做的一个项目:https://vipshop.github.io/ams/
假如全部用json编写,那么出现一个特殊场景,比如登录的密码需要在发送请求之前前端进行加密,这种如何解决,json又不能写代码,而且还有一个致命的缺点无法注释
@lawbc
假如全部用json编写,那么出现一个特殊场景,比如登录的密码需要在发送请求之前前端进行加密,这种如何解决,json又不能写代码,而且还有一个致命的缺点无法注释
// 以下是这个字段的配置 config.json
[
{
type:'input‘,
key:'password',
title:'密码',
required:true,
calc:'getMD5'
}
]
// fnLib.js ,约定可以使用的函数全部放在这里面
// 假设这是你的getMD5函数
function getMD5(value) {
// 这里是getMD5函数的实现,以下为伪代码
console.log('MD5 of ' + value + ' is calculated.');
// 返回计算结果,这里假设返回一个字符串
return 'md5-' + value;
}
export default {
getMD5: getMD5
};
// 业务解析
import lib from './fnLib'
// 对字段的处理
const beforeSubmit= (item:{}, yourValueObject:{})=>{
let key = item.key;
let val = yourValueObject[key];
let fnName = item.calc
if(fnName )
{
// 调用函数
if (typeof lib[fnName] === 'function') {
let result = lib[fnName ](val);
return result;
} else {
console.error('Function not found');
}
}
}
首先赞一个👍 我理解好处是修改后台库中的字段就可实时更新页面,避免生产上重复部署; 但采用json来定义页面结果相较于直接写代码工作量感觉并没有减少,而且编辑器各种插件也用不了,所以好奇实际写起来效率如何?