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工程師在等你加入哦
相關文章
相關標籤/搜索