ReactNative 进阶之Form表单组件封装

React Native封装Form表单组件

为何咱们在移动端开发中急须要一个完善的Form表单组件尼?作过移动端开发的小伙伴们应该都清楚,一个完整的App项目中避免不了要有登陆注册功能,用户信息,密码等一系列须要新用户填写信息的页面,这些页面的UI若是都是循序渐进的去绘制,实际上是作了不少无用功,由于大部分UI都长的差很少,就是有些文案类的略微不一样,既然这样,咱们将这些长的差很少的UI抽离成组件,在须要用到的地方,直接调用封装好的组件,这样极大的下降了编写代码量,大大的提升开发者的效率git

Form表单支持的可配置项

  • TextInput
  • TextArea
  • Button
  • ButtonGroup
  • CheckBox
  • Radio
  • Switch
  • DatePicker
  • CustomView
  • Selector
  • CustomAction

后续待添加的配置项

  • 地区选择
  • CustomSelector
  • 用户图像
  • 图片上传
  • 短信验证码
  • 登陆注册
  • 待补充

效果图

image

主要功能

后期完成登陆注册、身份认证等表单信息页面的开发,咱们只须要一个简单的配置文件便可搞定,没必要每次相同的表单项都从新绘制一遍UI。对于哪些不常见的表单项,咱们能够彻底使用自定义UI来搞定,这样一来,咱们在平时开发中的80%的表单需求都能轻松的搞定了github

核心代码

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

github.com/guangqiang-…bash

更多文章

  • 做者React Native开源项目OneM【500+ star】地址(按照企业开发标准搭建框架完成开发的):github.com/guangqiang-…:欢迎小伙伴们 star
  • 做者简书主页:包含60多篇RN开发相关的技术文章www.jianshu.com/u/023338566… 欢迎小伙伴们:多多关注多多点赞
  • 做者React Native QQ技术交流群:620792950 欢迎小伙伴进群交流学习
  • 友情提示:在开发中有遇到RN相关的技术问题,欢迎小伙伴加入交流群(620792950),在群里提问、互相交流学习。交流群也按期更新最新的RN学习资料给你们,谢谢你们支持!

小伙伴们扫下方二维码加入RN技术交流QQ群

QQ群二维码,500+ RN工程师在等你加入哦
相关文章
相关标签/搜索