React Native封装Form表单组件
2017-11-29 本文已影响492人
光强_上海
React Native封装Form表单组件
为什么我们在移动端开发中急需要一个完善的Form表单组件尼?做过移动端开发的小伙伴们应该都清楚,一个完整的App项目中避免不了要有登录注册功能,用户信息,密码等一系列需要新用户填写信息的页面,这些页面的UI如果都是按部就班的去绘制,其实是做了很多无用功,因为大部分UI都长的差不多,就是有些文案类的略微不同,既然这样,我们将这些长的差不多的UI抽离成组件,在需要用到的地方,直接调用封装好的组件,这样极大的降低了编写代码量,大大的提高开发者的效率
Form表单支持的可配置项
- TextInput
- TextArea
- Button
- ButtonGroup
- CheckBox
- Radio
- Switch
- DatePicker
- CustomView
- Selector
- CustomAction
后续待添加的配置项
- 地区选择
- CustomSelector
- 用户图像
- 图片上传
- 短信验证码
- 登录注册
- 待补充
效果图
image主要功能
后期完成登录注册、身份认证等表单信息页面的开发,我们只需要一个简单的配置文件即可搞定,不必每次相同的表单项都重新绘制一遍UI。对于哪些不常见的表单项,我们可以完全使用自定义UI来搞定,这样一来,我们在平时开发中的80%的表单需求都能轻松的搞定了
核心代码
renderFields(fields) {
let fieldCount = fields.length ? fields.length : 0
return fields.map((field, index) => {
let isLastField = true
if (fieldCount === index + 1 || fields[index + 1].title !== undefined) {
isLastField = false
}
if (field.title !== undefined && field.show !== false) {
return this.renderGroupForm(field)
} else {
let {show, type, label, subLabel, subTitle, ...other} = field
let otherProps = {...other}
Object.keys(otherProps).map((key, index) => {
if (key.indexOf('on') === 0 || key === 'callback' || key === 'dataFunc' || key === 'view') {
otherProps[key] = this.props[otherProps[key]]
}
})
let isEditable = !this.props.readOnly && !this._isReadOnly(field.readOnly)
if (show !== false) {
if (this.fieldsType[type]) {
if (type === 'TextInput') {
return (
<View
key={index}
style={[styles.row, !isLastField ? {borderBottomWidth: 1, borderBottomColor: commonStyle.lineColor} : null]}
>
<View style={[styles.content, isLastField ? styles.lastLine : null]}>
{
label ?
<View style={styles.leftPanel}>
<View style={styles.leftTitle}>
<Text style={{fontSize: 15, color: commonStyle.textBlockColor}}>{label}</Text>
<Text style={{fontSize: 20, color: commonStyle.red}}>{subLabel}</Text>
</View>
{
subTitle ?
<View style={styles.subTitle}>
<Text style={{fontSize: 12, color: commonStyle.textGrayColor}}>{subTitle}</Text>
</View> : null
}
</View> : null
}
<View style={styles.inputContainer}>
<TextInput
style={styles.textInput}
{...otherProps}
placeholderTextColor={commonStyle.placeholderTextColor}
underlineColorAndroid={'transparent'}
editable={isEditable}
value={this.state[field.key] !== undefined && this.state[field.key] !== null && this.state[field.key].toString()}
onChangeText={value => {
this.state[field.key] = value
this.setState(this.state)
let _obj = {}
_obj[field.key] = value
this.props.onChange && this.props.onChange(_obj)
}}
/>
</View>
</View>
</View>
)
} else if (type === 'Button') {
return (
<View
key={index}
style={[styles.row, !isLastField ? {borderBottomWidth: 1, borderBottomColor: commonStyle.lineColor} : null]}>
<View
style={[styles.content, isLastField ? styles.lastLine : null, {justifyContent: commonStyle.center}]}>
<Button
{...field}
{...otherProps}>
{field.text}
</Button>
</View>
</View>
)
} else if (type === 'ButtonGroup') {
return (
<View
key={index}
style={[styles.row, !isLastField ? {borderBottomWidth: 1, borderBottomColor: commonStyle.lineColor} : null]}>
<View style={[styles.content, isLastField ? styles.lastLine : null]}>
{
label ?
<View style={styles.leftPanel}>
<View style={styles.leftTitle}>
<Text style={{fontSize: 15, color: commonStyle.textBlockColor}}>{label}</Text>
<Text style={{fontSize: 20, color: commonStyle.red}}>{subLabel}</Text>
</View>
{
subTitle ?
<View style={styles.subTitle}>
<Text style={{fontSize: 12, color: commonStyle.textGrayColor}}>{subTitle}</Text>
</View> : null
}
</View> : null
}
<View style={{flex: 1, height: 49, flexDirection: commonStyle.row, alignItems: commonStyle.center, justifyContent: 'flex-end', marginRight: 10}}>
{
field.items.map((item, index) => {
let _cloneBtn = deepClone(item)
Object.keys(_cloneBtn).map((key, index) => {
if (key.indexOf('on') === 0) {
_cloneBtn[key] = this.props[_cloneBtn[key]]
}
})
if (typeof _cloneBtn.selected === 'boolean') {
return (
<Button
key={index}
style={[_cloneBtn.style, _cloneBtn.selected ? _cloneBtn.selectedStyle : null]}
textStyle={[_cloneBtn.textStyle, _cloneBtn.selected ? _cloneBtn.textSelectedStyle : null]}
{..._cloneBtn}
>
{_cloneBtn.text}
</Button>
)
} else {
return (
<Button
key={index}
style={[_cloneBtn.style, _cloneBtn.selected && _cloneBtn.selected() ? _cloneBtn.selectedStyle : null]}
textStyle={[_cloneBtn.textStyle, _cloneBtn.selected && _cloneBtn.selected() ? _cloneBtn.textSelectedStyle : null]}
>
{_cloneBtn.text}
</Button>
)
}
})
}
</View>
</View>
</View>
)
} else if (type === 'Switch') {
return (
<View
key={index}
style={[styles.row, !isLastField ? {borderBottomWidth: 1, borderBottomColor: commonStyle.lineColor} : null]}
>
<View style={[styles.content, isLastField ? styles.lastLine : null]}>
{
label ?
<View style={styles.leftPanel}>
<View style={styles.leftTitle}>
<Text style={{fontSize: 15, color: commonStyle.textBlockColor}}>{label}</Text>
<Text style={{fontSize: 20, color: commonStyle.red}}>{subLabel}</Text>
</View>
{
subTitle ?
<View style={styles.subTitle}>
<Text style={{fontSize: 12, color: commonStyle.textGrayColor}}>{subTitle}</Text>
</View> : null
}
</View> : null
}
<View style={styles.switch}>
<Switch
disabled={!isEditable}
value={this.state[field.key] !== undefined && this.state[field.key] !== null && this.state[field.key]}
onValueChange={value => {
this.state[field.key] = value
this.setState(this.state)
let _obj = {}
_obj[field.key] = value
this.props.onChange && this.props.onChange(_obj)
}}
/>
</View>
</View>
</View>
)
} else if (type === 'View') {
return (
<View key={index}
style={[styles.row, !isLastField ? {borderBottomWidth: 1, borderBottomColor: commonStyle.lineColor} : null]}>
<View
key={index}
style={[styles.content, isLastField ? styles.lastLine : null]}>
{
label ?
<View style={styles.leftPanel}>
<View style={styles.leftTitle}>
<Text style={{fontSize: 15, color: commonStyle.textBlockColor}}>{label}</Text>
<Text style={{fontSize: 20, color: commonStyle.red}}>{subLabel}</Text>
</View>
{
subTitle ?
<View style={styles.subTitle}>
<Text style={{fontSize: 12, color: commonStyle.textGrayColor}}>{subTitle}</Text>
</View> : null
}
</View> : null
}
<View
ref={'customView'}
style={styles.view}
{...field}
{...otherProps}
>
{otherProps.view}
</View>
</View>
</View>
)
} else if (type === 'TextArea') {
let Comp = this.fieldsType[type]
return (
<View key={index}
style={[styles.row, !isLastField ? {borderBottomWidth: 1, borderBottomColor: commonStyle.lineColor} : null]}>
<View
key={index}
style={[styles.content, isLastField ? styles.lastLine : null]}>
{
label ?
<View style={styles.leftPanel}>
<View style={styles.leftTitle}>
<Text style={{fontSize: 15, color: commonStyle.textBlockColor}}>{label}</Text>
<Text style={{fontSize: 20, color: commonStyle.red}}>{subLabel}</Text>
</View>
{
subTitle ?
<View style={styles.subTitle}>
<Text style={{fontSize: 12, color: commonStyle.textGrayColor}}>{subTitle}</Text>
</View> : null
}
</View> : null
}
<Comp
ref={(ref) => this._component[field.key] = ref}
name={field.key}
value={this.state}
editable={isEditable}
{...field}
{...otherProps}
onChange={this.props.onChange && this.props.onChange()}
/>
</View>
</View>
)
} else {
let Comp = this.fieldsType[type]
return (
<View key={index}
style={[styles.row, !isLastField ? {borderBottomWidth: 1, borderBottomColor: commonStyle.lineColor} : null]}>
<View
key={index}
style={[styles.content, isLastField ? styles.lastLine : null]}>
{
label ?
<View style={styles.leftPanel}>
<View style={styles.leftTitle}>
<Text style={{fontSize: 15, color: commonStyle.textBlockColor}}>{label}</Text>
<Text style={{fontSize: 20, color: commonStyle.red}}>{subLabel}</Text>
</View>
{
subTitle ?
<View style={styles.subTitle}>
<Text style={{fontSize: 12, color: commonStyle.textGrayColor}}>{subTitle}</Text>
</View> : null
}
</View> : null
}
<View style={{flex: 1}}>
<Comp
ref={(ref) => this._component[field.key] = ref}
name={field.key}
value={this.state}
editable={isEditable}
{...field}
{...otherProps}
descValue={field.name}
onChange={this.props.onChange && this.props.onChange()}
/>
</View>
</View>
</View>
)
}
} else {
return (
<View key={index}
style={[styles.row, !isLastField ? {borderBottomWidth: 1, borderBottomColor: commonStyle.lineColor} : null]}>
<View
key={index}
style={[styles.content, isLastField ? styles.lastLine : null]}>
{
label ?
<View style={styles.leftPanel}>
<View style={styles.leftTitle}>
<Text style={{fontSize: 15, color: commonStyle.textBlockColor}}>{label}</Text>
<Text style={{fontSize: 20, color: commonStyle.red}}>{subLabel}</Text>
</View>
{
subTitle ?
<View style={styles.subTitle}>
<Text style={{fontSize: 12, color: commonStyle.textGrayColor}}>{subTitle}</Text>
</View> : null
}
</View> : null
}
<View style={{ flex: 1, height: 49 }}>
<CustomAction
type={type}
ref={(ref) => this._component[field.key] = ref}
name={field.key} value={this.state}
{...field}
{...otherProps}
editable={isEditable}
onChange={this.props.onChange}
descValue={field.name}
/>
</View>
</View>
</View>
)
}
}
}
})
}
详细的使用方式请参照项目源码OneM
https://github.com/guangqiang-liu/OneM
福利时间
- 作者React Native开源项目OneM地址(按照企业开发标准搭建框架完成开发的):https://github.com/guangqiang-liu/OneM (欢迎小伙伴们 star)
- 作者简书主页:包含50多篇RN开发相关的技术文章http://www.jianshu.com/u/023338566ca5 (欢迎小伙伴们:多多关注,多多点赞)
- 作者React Native QQ技术交流群:620792950 欢迎小伙伴进群交流学习
- 友情提示:在开发中有遇到RN相关的技术问题,欢迎小伙伴加入交流群(620792950),在群里提问、互相交流学习。交流群也定期更新最新的RN学习资料给大家,谢谢支持!