前语
了解我的朋友或许会知道,我一向是不写热门的。为什么不写呢?是因为我不重视热门吗?其实也不是。有些事情我仍是很重视的,也确实有不少想法和观念。
但我一向奉行一个原则,便是:要做有生命力的O – J v ! | , * /内容。
这篇文章是一篇运用性极强的文章,咱们经过一个实践的运用场景,去解决某一类的问题,供给一种或许几种解决计划,来探索技能的魅力。接下来笔者首要剖析表单定制渠道的完结思路和技能6 Y 1 H q计划,来完结一个. ] % , e : b J 类似于金数据或许问卷星一样的表单装备渠道,咱们也能够依据此计划,扩展出功用更加强壮的可视化渠道。
正文
为什么要做一个这样的渠道呢?一方面是因为笔者多年来一E l )向服务于B端产品,关e E `于动态表单以9 H K w S ( k及装备化表单有必定G I H e = U 4 |的项目f t a + – 5 v L积累,并且深知A k x – 6 w 1 f装备化表单的价值D W _ a 2 6 o地点。举一个很传统的B端表单装备化的比方:传统2B企业在供给saas服务时,为了满意不同企业的定制化需求,往往会给企业客户供给定制化或许自在装备的功用,如下图:
关g b 6 ] N l B `于saas体系而言,软件即服务~ _ P 5 : Q } ~,在供给根底服务的同时,相同要满意用户个性化需求,所以传统的saas软件供给商往往会供给给客户自在装备的空间,d 6 3 M N这种自在装备的桥梁便是经过表单,举一个简单的比方:
经过这种方法就能够定制不同风格的企业产品,这儿仅仅举了个比较简单的比方,往往实践项目中会更加杂乱,C n G [ y ) C t或许会有几十个装备项,当然这种形式是比较传统的装备化计划,也仅仅是saas软件供给的很小的一个服务模块。目前主流的做法是选用可视化计划,并且国7 l N @ ;内也有十分老练的计划,但m D 1 k根本的思想是一起的,只不? Z I ) ! B过后者的体验更好,操作难度更低。
笔者简单介绍一下s) ? J taas,便利咱们更简单了解其形式:
saas(软件即服务)是一种云核算产品,为用户供给对供货商云端软件的拜访X D q b E ` o。用户无需在其本地设备上装置运用。相反,运用驻留在远程云网络中,经过 Web 或 API 进行拜访。经过运用,用户能够存储和剖析数据,并可进行项目协作。
类似的云核算产品也有许多,比方Paas– O |(渠道即服务),Iaas(根底架构即服务)等,感兴趣的朋友能够学习了解一下。
以上介绍更多的是为了让咱们了解笔者规划这套渠W l } ? W #道的根本布景,咱们还能够举个更实践的比方便是, N 3 ; 4 9金数据或许问卷星的表单装备形式,用户能够在办理后v j E b 4 E台定制自己的表单,并生成一个可拜访的链接来向方针用户发放问卷,填写信息m ; K u o 8 [ Z .,搜集信息,最终完结数据剖~ R v g析的意图。
本文介绍的表单定制渠道,也相同支撑表单办理,表单数据剖析, 表单数据搜集, 表单定制等功用, 笔者将选用比较了解的技能栈react以及第三方ui库antd4.0来开发, 后端选用node + koa来规划路由接口.
规划思路
完结作用与剖析
1. 表单定制办理列表
办理列表首要用来检查咱们装备的表单模板,剖析不同表单模板搜集的数据,对表单d E K n 5 . V &模板进行修9 u = z正删去Q [ x 3 Q =等操作.
2. 表单定制页面
由上图可知表单定制页面首要用来修正自定义表单模板,咱们能够增加表单标题,表单字段等,目前供给了几种自定义表单控件如下:
- 文本框
- 多行文本框
- 下拉框
- 单选框
- 复选框
- 文件上传控件
根本( L e M ) R ` = .涵盖了咱们所需求的一切表单事务场# [ . k [ 2 N G景.由上图可知咱d x W们? F ^ 8 – [ 5 [能够在任意位置插入自定义字段,同时能够修正修正删去表单字段.假如想象力再大一点,咱们能够依据它来完结不o k / F仅仅是表单问卷型运用,还能够完结答题,发布内容等场景.(后期可支撑富文本控件)
3. 草稿办理
草稿箱规划的意图是便利运用者在装备表单的进程中不确定是否契合需求或许因为某种临时性行为而无法持续装备,这个时候a x @ P d 8能够将以装备好的内容存入草稿箱,下次持续修正,所9 B 3 v以笔者专门规划M n P !了草稿箱办理列表,一旦用户存在草稿,会在办理页面告诉用户并显现草稿的数量.作为一个追求体验的技能人,这一块的规划仍是适当有必要的.
4. 生成前台表N = & , % x w @单拜g V | 2 R c Y E x访链接
当咱们装备好表单之后,咱们点击保存, 会生成一个前台拜访地址,实时拜访表单信息,如下图为点击链接之后的页面:
咱们也能够依据自己的风y 8 v g格,规划自己的表单录入页面, 具体怎么完结这样的进程, 后边我会具体介绍.
5. 检查用户已有数据录入
咱们能够经过点击”检查数据”来拜访搜集到的表单数据,并经过可视化的工具对数据做剖析比较,同时咱们也能够在数据列表中删去数据,来操控咱们数据展示的纯洁9 & 6 & F S O V I.
6. 表单数据剖析
搜集到f @ s数据只有,咱们会自动集成几个可视化组件来剖析表单数据,h O X x n ; Q v b以上是笔者列出的几0 T W = o 个可视化组件,依据antv G2来封装.
运用场景
以上首要介绍了自R J 0 @ s定义表单定制渠道的一些功用和交互作用, 咱们能够运用该渠道做许多有意思的事情.因为表单的抽象f 4 P H # X 7是数据,咱们. = 4拿到定制化的表单json数据之后,咱们能够有不同的展示形式,比方用户的问卷调查, 网站渠道的投票, 答a K K } h * = o 题页面B M U e :, 发布动态等功用,如下图装备:
以上装备能够完结类似于微信的发布朋友圈的功用, 然后咱B ^ K % y _ ? U们能够经过前端的手法依据用h R # x @ } w _户发表的数据烘托成一个朋友圈列表.
假如咱们再打开自己的脑洞,咱们能够这样装备,装备一个这样的表单,表单包含一个文件上传控件和n个文本输入控件,如下图:
将这样的表单装备到H5办理模块,咱们只需} M T 3 h * E e A求上传三张图,然后填写好对应的配文,然后运用市面上老练的H5全屏滚动插件,就能轻松的定制各种H5活动页面了。该计划已被笔者的许多子体系运用,作用仍是十分好的。
当然依据该渠道甚至能直接装备小型的宣扬网站,还有更多想象空间,等待咱们去挖掘。
代码完结
要想开发这样一个表单定制渠道, 核心在于怎么完结表单动态装备的机制.这儿笔者将其划分为两部分:根底表单物料和表单修正生成器, 如下图所示拆分图:
接下来咱们一步步完结以上两个核心模块。
1. 根底表单物料
根底表单物料首要是为了用户挑选自定义表单控件运用,咱们常用的表单动态烘托有m6 U nap循环+条件判别和单层map+对象法,前者假如要烘托一个动态表单,或许完结D k Q # j 9 N c如下:
{
list( z O P w a P.map((item, i) => {
return <React.7 7 ] -FraN z 4 # j bgment key={i}>
{
item.ty O c 0 9 j #ype == 7 - 8 x I J g 1= 'input' && <Input />
}
{
item.type === 'radio' && <Radio />
}
// ..i O c j p.
</React.FragmL } Uent>
})
}
但是这B ) R j样做有个显着的缺陷便r x d 8 –是会产生许^ h B j { = H + C多没必要的判别,假如关q i ^ ) f $ 0 {于杂乱表单,功用往往很低,所以笔者选用后者来完结,杂乱度能够降到O(n).咱们先来做装备模版:
// 根底模版数据
const tpl = [
{
label: '文本框K } f %',
placeholder: '请输入内容',
type: 'text',
value: '',
index: uuid(5)
},
{
label: '单选框o o N a',
type: 'radioy { & = U q',
option: [{label: '男', value: 0}, {label:x ; & ; } _ ) w x '女', value: 1}],
index: uuid(5)
},
{
label: '复选框',
type: 'checkbox',
option: [{la : b B v B Ybel: '男', valug D 6 8 3 B X me: 0}, {label: '女', value: 1}],
index: uuid(5)
},
{
label: '多行文本',
placeholder: '请输入内容',
type: 'tes Y q % 2 Xxtax t y 3rea',
i# & g % V p H 9ndex: uuid(5)
},
{
label: '挑选框',
placeholder: '请挑选',
type: 'select',
option: [{labe6 K ; n (l: '中国', value: 0}, {label: '俄罗斯', value: 1}],
iw / d W , yndex: uuid(5)
},
{
label: '文件上传',
type: t 4 - ~ ,: 'upload',
index: uu+ ~ n T q q f Pid(5)
}
]
// 模版烘托组件
const tplMap = {
te{ 2 / % ? ! {xt: {
component: (props) => {
const { placeholder, labG [ M l Ael } = props
retX F ourn <div className={u ; A ystyles.fieldOption}><span className=b e l 5 + 4 5 9{styles.fieldLabelN i !}>{label}:</span>&l& ! r = ] 8t;Input placeholder=Z 1 J j N T |{placeholder} /></div>
}
},
textarea:e B - t , M x {
component: (props) =>X N l; {
const+ Z j C F Q e L J { placeholder, label } = props
return <div className={styles.fieldOption}><span classa M o A / zName={$ [ @ Ostyles.fieldLabel}>{label}:</span><TextAreao l ( d V g k placeholp j 9 J U oder={placeholder} /></div>
}
},
radio: {
component: (props) => {
con] 9 w ] u A c |st { option, label } = props
return <S { A ~ W T 5div className={styles.fieldOption}>
&4 s } 8 %lt;span className={styles.fieldLabel}>{label}:</span>
<Radio.Group>
{
option && option.map((item, i) =>n X d j x x k Y; {
return <Radio style={radioStyle} value={itemo 6 l l l U (.value} key={item.label}>
{ item.label }
</Radio>
})
}
</Radio.Gr& 4 Joup>
</div>
}
},
checkbox: {
component: (props) => {
con8 , . * 7 `st { option, label } = props
return <dif # p M Uv className={styles.fieldOption}>
<span className={styles.fieldLabel}>{label}! k [ o N d:</span>
<CheckH % D ?box.Group>
<Row>
{
option && option.map(item => {
return <Col span={16} k _ Hey={item.label}>
<Checkbox valI F Eue={item.value} style={{ lineHeight: '8 d $ 1 . c32pxl 2 u v W Q e' }}s ( X U , u p .>
{ item.label }
</Checkbox>
</Col>
})
}
</Row>
</Checkbox.Grof H Z _ Z #up>
</Q B ; m Udiv>
}
},
select: {
component: (props) =>t C = J _; {
const { placeholder, option, label } = props
return <div className={styles.fieldOption}>
<span className={styles.fieldLabel# H ^ m I )}>{label}:</span>G 1 P p E
<Select placeholder={placeholder} ss [ u , * z P etyle={{width: '100%'}}>
{
option &, # 4 g R $ ] mamp9 C B y m W;&a= 2 mmp; option.map(item => {
return <Option value={item.va@ Z M r K d U Elue} key={item.label}>{itema @ |.label}</Option>
})
}
</Select>
</div>
}
},
upload: {
component: (props) => {
r, 6 N O .eturn <div className={styles.fieldOption}>
<span className={styles.fieldLabel}>{E | bpro# x 1ps.label}:</span>
<Upload
listType="picture-card"
className="avatar-uploader"
shoK 8 V , ) TwUploadList={false}
action="https://www.mocH , & 8 C 8 _ S kky.io/v2/5cc8019d300000980a055e76i k 3 S , V y %"
>~ p s q 8 X $ [;
<t t Ldiv>$ Q ) );+</div>
</Upload>
</div>
}
}
}
export {
tpl,
tplMap
}
根底物料在下图所示中运用:
当咱们要增加一个表单项时,咱们就能够在左面预览操作区看到增加的项,并能够依据表单修正生成器来修正表单字段。
2. 表单修正生成器
表单修正生成器I H 8 O分为2部分, 第一部分是用来生成表单项的容器组件,封装了增加,删去,修正操作功用,代码如下:W H V b ~ 6 V
// 表单容器组件
const BaseFormEl = (props) => {
const {isEdit, onEdit, onDel, onAdd} = props
const handleE6 X 7 : x V 3 : Mdit = (v) => {
onEdit && onEdit(v)
}
return <div className={styles.formControl}>
<div className={styles.formItem}>{ props.children }</div>
<div className={styles.acta U A 0 3ionBar}>
<span clae * X } j y j XssName={styles.acti, M t D ] a k 4 oonItem} onCl{ s { 6 W m Hick={onDel}><Ml 2 HinusCircleOutlined /></span>
<span className={ste ) U l X & * M #yles.actionI ! & b e U ntem} onClick={onAdd}><PlusCircleOutlined /></spn ^ { 9 J e ^ {an>
<span className={styles.2 5 @ l F 4 M ? #actionItem} onClick={handleEdit}><EditOutline$ c I # 7 e Od /></span>
</div>7 E 2;
&lN M [ * ` - ` s $t;/div>
}
第二部分首要用来烘托操作区模版,依据BaseFormEl包装不同类型的表单s p 4 u k | V 9 S组件, 这儿举一个比较杂乱的select来阐明,其他表单控件类似:
const formMap = {
title: {},
text: {},
textarea: {},
radio: {},
checkbox: {},
select: {
compo6 q E m wnent: (props) => {
const { onDel, oK } % Y . BnAdd, onEdit, curIndex, index, type, label, placeholder, r} e k B u [ q Wequired, message, option } = props
return <BaseFormEl
onDel={onDel^ E |.bind(this a, index)}
onAdd={onAdd.bind(this, index)}
onEdit={onEdit.bind(this, {index, type, placeholder, label, optio B A M Un, required})}
isEdit={curInZ b _ c ddex === index}
>
<Form.Item name={label} label={label} rules={[{ message, rk 2 nequired }]h K = V ; } s }}>
<Select placeholder={placeholder}>
{
option && option.map(item =>- P ; e O O 1 2 {
return <Option value={item.value} keyx l i={item.label}>{item.label}&lM . E D I L Zt;/O( Z : 3 ? { Sption>
})
}
</Select>
&lh p s C E y 7t;/Form.Item>
</BaseFormEl>
},
editAttrs: [
{
titl& D w l Xe: '字段名称',
key: 'label'
},
{
title: '选项',
key: 'option'
},
{
title: '提示文本',
key: 'placeholder'
},
{
title: '是否必填',
key: 'required'
},
]
},R H V
uploaB 3 * )d: {R # d .}
}
edi^ U +tAttrs首要用来烘托修正列表,阐明哪些表单项能够修正,这部分代码比较简单,这儿直接用图举例:
最终咱们来烘托表单生成器组件:
export default (props) => {
const {
formDa{ 3 } Y , C Pta,
handleDelete,
handleAdd,
handleEdit,
curEditRowIdx
} = props
return <Form name="cC n | ;ustomForm">
{
formData &&e K 7 z R X 4 a { formData.map(item => {
let CP = formMap[item.type].comT q f d oponent
return <CP {...item} key={item.index}
onDel={handleDelete}
onAdd={handleAdd}+ i ; r ] ^ $
on` 7 L z ; & X 9Edit={handleEdit}
curIndex={curE_ 3 B I t ! * , PditRowIdx}
/>
})
}
</Form&gc q L x 9 Ht;
}
至此,根本功* : x s / ~用模块现已开发完结,咱们只需求将这些物f O i / U # – | K料和组件导入到修正页面,依据事务来操作和请求即可。因为完结该案例仍是有必定杂v ~ ( l g S G 0乱度的,笔者没有将一切组件都逐个写出来,希望r } % _为咱们供给一个考虑空间,后续笔者将会把该渠道整合到笔者的开源CMS体系中,供咱们学习运用[ S q i。有关nodp : Q c kejs部分的内容,因为笔者后期会陆续整理,假如有其他疑+ 4 v h K ] 2 o问,能够和笔者) F / L B N Z s多交流。
最终
假如想学习更多H5游戏, webpack,node,gulp,css32 ] f 2 V ~ 3,javascript,nodeJS,canvas数据可视化等前端知识和实战[ Y –,欢t e % |迎在公号《趣谈前端》参加咱们的技能群一起学习讨论,一起探索前端的鸿沟。
更多推荐
- 程序员必备的几种常见排序算~ Q $ Q法和搜索算法总结
- 几个十分有意思的javascrip: % $ B I # w &t知识点总结
- 前端进阶之从零到一完结单向 &aV K 3 b w S x dmp; 双向链表
- 微前k : d B f G M N P端架构初探以及我的前端技能盘点
- 运用nodeJs开发自己的图床运用
- 依据nodeJS从0到1完结一个CMS全栈项目(上)
- 依据nodeJS从0到1完结一个CMS全栈项目(中)(含源码)
- CMS全栈项目之Vue和React篇(下)(含源码)
- 5分钟教你用nodeJS手写一个mock数据服务器
- 从零到一教你依据vue开P i V 3 D发一个组件库
- 从0到1教你搭建前端团队的组件体系(高级进阶必备l w ( })b h $ f B ` i
- 10分钟教你手写8个常用的自定义hooks
- 15分钟带你了解前端工程师必} M E y c N %知的javascript规划形式(附具体思想导图和源码)
- 《前端实战总结》G ; m F @ q 2 C –之运用postMessage完结可插拔的跨域聊天机器人