问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

如何对reactnative封装

发布网友 发布时间:2022-05-14 15:03

我来回答

2个回答

懂视网 时间:2022-05-14 19:24

本篇文章给大家带来的内容是关于如何封装一个React Native多级联动(代码实现),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

背景

肯定是最近有一个项目,需要一个二级联动功能了!
本来想封装完整之后,放在github上面赚星星,但发现市面上已经有比较成熟的了,为什么我在开发之前没去搜索一下(项目很赶进度),泪崩啊,既然已经封装就来说说过程吧

任务开始

一. 原型图或设计图

在封装一个组件之前,首先你要知道组件长什么样子,大概的轮廓要了解

2189247561-5ba0a0c7927dd_articlex.jpg

二. 构思结构

在封装之前,先在脑海里面想一下

1. 这个组件需要达到的功能是什么?

改变一级后,二级会跟着变化,改变二级,三级会变,以此类推,可以指定需要选中的项,可以动态改变每一级的值,支持按需加载

2. 暴露出来的API是什么?

// 已封装的组件(Pickers.js)
import React, { Component } from 'react'
import Pickers from './Pickers'

class Screen extends Component {
 constructor (props) {
 super(props)
 this.state = {
 defaultIndexs: [1, 0], // 指定选择每一级的第几项,可以不填不传,默认为0(第一项)
 visible: true, // 
 options: [ // 选项数据,label为显示的名称,children为下一级,按需加载直接改变options的值就行了
 {
  label: 'A',
  children: [
  {
  label: 'J'
  },
  {
  label: 'K'
  }
  ]
 },
 {
  label: 'B',
  children: [
  {
  label: 'X'
  },
  {
  label: 'Y'
  }
  ]
 }
 ]
 }
 }
 onChange(arr) { // 选中项改变时触发, arr为当前每一级选中项索引,如选中B和Y,此时的arr就等于[1,1]
 console.log(arr)
 }
 onOk(arr) { // 最终确认时触发,arr同上
 console.log(arr)
 }
 render() {
 return (
 <View style={styles.container}>
 <Pickers
  options={this.state.options}
  defaultIndexs={this.state.defaultIndexs}
  onChange={this.onChange.bind(this)}
  onOk={this.onOk.bind(this)}>
 </Pickers>
 </View>
 )
 }
}

API在前期,往往会在封装的过程中,增加会修改,根据实际情况灵活变通

3. 如何让使用者使用起来更方便?

用目前比较流行的数据结构和风格(可以借鉴其它组件),接口名称定义一目了然

4. 如何能适应更多的场景?

只封装功能,不封装业务

三. 开始写代码

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import {
 StyleSheet,
 View,
 Text,
 TouchableOpacity,
} from 'react-native'

class Pickers extends Component {
 static propTypes = {
 options: PropTypes.array,
 defaultIndexs: PropTypes.array,
 onClose: PropTypes.func,
 onChange: PropTypes.func,
 onOk: PropTypes.func,
 }

 constructor (props) {
 super(props)
 this.state = {
 options: props.options, // 选项数据
 indexs: props.defaultIndexs || [] // 当前选择的是每一级的每一项,如[1, 0],第一级的第2项,第二级的第一项
 }
 this.close = this.close.bind(this) // 指定this
 this.ok = this.ok.bind(this) // 指定this
 }
 close () { // 取消按钮事件
 this.props.onClose && this.props.onClose()
 }

 ok () { // 确认按钮事件
 this.props.onOk && this.props.onOk(this.state.indexs)
 }
 onChange () { // 选项变化的回调函数

 }
 renderItems () { // 拼装选择项组

 }

 render() {
 return (
 <View
 style={styles.box}>
 <TouchableOpacity
  onPress={this.close}
  style={styles.bg}>
  <TouchableOpacity
  activeOpacity={1}
  style={styles.dialogBox}>
  <View style={styles.pickerBox}>
  {this.renderItems()}
  </View>
  <View style={styles.btnBox}>
  <TouchableOpacity
  onPress={this.close}
  style={styles.cancelBtn}>
  <Text
   numberOfLines={1}
   ellipsizeMode={"tail"}
   style={styles.cancelBtnText}>取消</Text>
  </TouchableOpacity>
  <TouchableOpacity
  onPress={this.ok}
  style={styles.okBtn}>
  <Text
   numberOfLines={1}
   ellipsizeMode={"tail"}
   style={styles.okBtnText}>确认</Text>
  </TouchableOpacity>
  </View>
  </TouchableOpacity>
 </TouchableOpacity>
 </View>
 )
 }
}

选择项组的拼装是核心功能,单独提出一个函数(renderItems)来,方便管理和后期维护

 renderItems () { // 拼装选择项组
 const items = []
 const { options = [], indexs = [] } = this.state
 const re = (arr, index) => { // index为第几级
 if (arr && arr.length > 0) {
 const childIndex = indexs[index] || 0 // 当前级指定选中第几项,默认为第一项
 items.push({
  defaultIndex: childIndex,
  values: arr //当前级的选项列表
 })
 if (arr[childIndex] && arr[childIndex].children) {
  const nextIndex = index + 1
  re(arr[childIndex].children, nextIndex)
 }
 }
 }
 re(options, 0) // re为一个递归函数
 return items.map((obj, index) => {
 return ( // PickerItem为单个选择项,list为选项列表,defaultIndex为指定选择第几项,onChange选中选项改变时回调函数,itemIndex选中的第几项,index为第几级,如(2, 1)为选中第二级的第三项
 <PickerItem
  key={index.toString()}
  list={obj.values}
  defaultIndex={obj.defaultIndex}
  onChange={(itemIndex) => { this.onChange(itemIndex, index)}}
  />
 )
 })
 }

PickerItem为单个选择项组件,react native中的自带Picker在安卓和IOS上面表现的样式是不一样的,如果产品要求一样的话,就在PickerItem里面改,只需提供相同的接口,相当于PickerItem是独立的,维护起来很方便

// 单个选项
class PickerItem extends Component {
 static propTypes = {
 list: PropTypes.array,
 onChange: PropTypes.func,
 defaultIndex: PropTypes.number,
 }

 static getDerivedStateFromProps(nextProps, prevState) { // list选项列表和defaultIndex变化之后重新渲染
 if (nextProps.list !== prevState.list ||
 nextProps.defaultIndex !== prevState.defaultIndex) {
 return {
 list: nextProps.list,
 index: nextProps.defaultIndex
 }
 }
 return null
 }

 constructor (props) {
 super(props)
 this.state = {
 list: props.list,
 index: props.defaultIndex
 }
 this.onValueChange = this.onValueChange.bind(this)
 }

 onValueChange (itemValue, itemIndex) {
 this.setState( // setState不是立即渲染
 {
 index: itemIndex
 },
 () => {
 this.props.onChange && this.props.onChange(itemIndex)
 })

 }

 render() {
 // Picker的接口直接看react native的文档https://reactnative.cn/docs/picker/
 const { list = [], index = 0 } = this.state
 const value = list[index]
 const Items = list.map((obj, index) => {
 return <Picker.Item key={index} label={obj.label} value={obj} />
 })
 return (
 <Picker
 selectedValue={value}
 style={{ flex: 1 }}
 mode="dropdown"
 onValueChange={this.onValueChange}>
 {Items}
 </Picker>
 )
 }
}

renderItems()中PickerItem的回调函数onChange

 onChange (itemIndex, currentIndex) { // itemIndex选中的是第几项,currentIndex第几级发生了变化
 const indexArr = []
 const { options = [], indexs = [] } = this.state
 const re = (arr, index) => { // index为第几层,循环每一级
 if (arr && arr.length > 0) {
 let childIndex
 if (index < currentIndex) { // 当前级小于发生变化的层级, 选中项还是之前的项
  childIndex = indexs[index] || 0
 } else if (index === currentIndex) { // 当前级等于发生变化的层级, 选中项是传来的itemIndex
  childIndex = itemIndex
 } else { // 当前级大于发生变化的层级, 选中项应该置为默认0,因为下级的选项会随着上级的变化而变化
  childIndex = 0
 }
 indexArr[index] = childIndex
 if (arr[childIndex] && arr[childIndex].children) {
  const nextIndex = index + 1
  re(arr[childIndex].children, nextIndex)
 }
 }
 }
 re(options, 0)
 this.setState(
 {
 indexs: indexArr // 重置所有选中项,重新渲染
 },
 () => {
 this.props.onChange && this.props.onChange(indexArr)
 }
 )
 }

总结

市面上成熟的多级联动很多,如果对功能要求比较高的话,建议用成熟的组件,这样开发成本低,文档全,团队中其他人易接手。如果只有用到里面非常简单的功能,很快就可以开发好,建议自己开发,没必要引用一个庞大的包,如果要特殊定制的话,就只有自己开发。无论以上哪种情况,能理解里面的运行原理甚好

主要说明在代码里面,也可以直接拷贝完整代码看,没多少内容,如果需要获取对应值的话,直接通过获取的索引查对应值就行了

完整代码

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import {
 StyleSheet,
 View,
 Text,
 Picker,
 TouchableOpacity,
} from 'react-native'

// 单个选项
class PickerItem extends Component {
 static propTypes = {
 list: PropTypes.array,
 onChange: PropTypes.func,
 defaultIndex: PropTypes.number,
 }

 static getDerivedStateFromProps(nextProps, prevState) { // list选项列表和defaultIndex变化之后重新渲染
 if (nextProps.list !== prevState.list ||
 nextProps.defaultIndex !== prevState.defaultIndex) {
 return {
 list: nextProps.list,
 index: nextProps.defaultIndex
 }
 }
 return null
 }

 constructor (props) {
 super(props)
 this.state = {
 list: props.list,
 index: props.defaultIndex
 }
 this.onValueChange = this.onValueChange.bind(this)
 }

 onValueChange (itemValue, itemIndex) {
 this.setState( // setState不是立即渲染
 {
 index: itemIndex
 },
 () => {
 this.props.onChange && this.props.onChange(itemIndex)
 })

 }

 render() {
 // Picker的接口直接看react native的文档https://reactnative.cn/docs/picker/
 const { list = [], index = 0 } = this.state
 const value = list[index]
 const Items = list.map((obj, index) => {
 return <Picker.Item key={index} label={obj.label} value={obj} />
 })
 return (
 <Picker
 selectedValue={value}
 style={{ flex: 1 }}
 mode="dropdown"
 onValueChange={this.onValueChange}>
 {Items}
 </Picker>
 )
 }
}

// Modal 安卓上无法返回
class Pickers extends Component {
 static propTypes = {
 options: PropTypes.array,
 defaultIndexs: PropTypes.array,
 onClose: PropTypes.func,
 onChange: PropTypes.func,
 onOk: PropTypes.func,
 }
 static getDerivedStateFromProps(nextProps, prevState) { // options数据选项或指定项变化时重新渲染
 if (nextProps.options !== prevState.options ||
 nextProps.defaultIndexs !== prevState.defaultIndexs) {
 return {
 options: nextProps.options,
 indexs: nextProps.defaultIndexs
 }
 }
 return null
 }
 constructor (props) {
 super(props)
 this.state = {
 options: props.options, // 选项数据
 indexs: props.defaultIndexs || [] // 当前选择的是每一级的每一项,如[1, 0],第一级的第2项,第二级的第一项
 }
 this.close = this.close.bind(this) // 指定this
 this.ok = this.ok.bind(this) // 指定this
 }
 close () { // 取消按钮事件
 this.props.onClose && this.props.onClose()
 }

 ok () { // 确认按钮事件
 this.props.onOk && this.props.onOk(this.state.indexs)
 }
 onChange (itemIndex, currentIndex) { // itemIndex选中的是第几项,currentIndex第几级发生了变化
 const indexArr = []
 const { options = [], indexs = [] } = this.state
 const re = (arr, index) => { // index为第几层,循环每一级
 if (arr && arr.length > 0) {
 let childIndex
 if (index < currentIndex) { // 当前级小于发生变化的层级, 选中项还是之前的项
  childIndex = indexs[index] || 0
 } else if (index === currentIndex) { // 当前级等于发生变化的层级, 选中项是传来的itemIndex
  childIndex = itemIndex
 } else { // 当前级大于发生变化的层级, 选中项应该置为默认0,因为下级的选项会随着上级的变化而变化
  childIndex = 0
 }
 indexArr[index] = childIndex
 if (arr[childIndex] && arr[childIndex].children) {
  const nextIndex = index + 1
  re(arr[childIndex].children, nextIndex)
 }
 }
 }
 re(options, 0)
 this.setState(
 {
 indexs: indexArr // 重置所有选中项,重新渲染
 },
 () => {
 this.props.onChange && this.props.onChange(indexArr)
 }
 )
 }
 renderItems () { // 拼装选择项组
 const items = []
 const { options = [], indexs = [] } = this.state
 const re = (arr, index) => { // index为第几级
 if (arr && arr.length > 0) {
 const childIndex = indexs[index] || 0 // 当前级指定选中第几项,默认为第一项
 items.push({
  defaultIndex: childIndex,
  values: arr //当前级的选项列表
 })
 if (arr[childIndex] && arr[childIndex].children) {
  const nextIndex = index + 1
  re(arr[childIndex].children, nextIndex)
 }
 }
 }
 re(options, 0) // re为一个递归函数
 return items.map((obj, index) => {
 return ( // PickerItem为单个选择项,list为选项列表,defaultIndex为指定选择第几项,onChange选中选项改变时回调函数
 <PickerItem
  key={index.toString()}
  list={obj.values}
  defaultIndex={obj.defaultIndex}
  onChange={(itemIndex) => { this.onChange(itemIndex, index)}}
  />
 )
 })
 }

 render() {
 return (
 <View
 style={styles.box}>
 <TouchableOpacity
  onPress={this.close}
  style={styles.bg}>
  <TouchableOpacity
  activeOpacity={1}
  style={styles.dialogBox}>
  <View style={styles.pickerBox}>
  {this.renderItems()}
  </View>
  <View style={styles.btnBox}>
  <TouchableOpacity
  onPress={this.close}
  style={styles.cancelBtn}>
  <Text
   numberOfLines={1}
   ellipsizeMode={"tail"}
   style={styles.cancelBtnText}>取消</Text>
  </TouchableOpacity>
  <TouchableOpacity
  onPress={this.ok}
  style={styles.okBtn}>
  <Text
   numberOfLines={1}
   ellipsizeMode={"tail"}
   style={styles.okBtnText}>确认</Text>
  </TouchableOpacity>
  </View>
  </TouchableOpacity>
 </TouchableOpacity>
 </View>
 )
 }
}

const styles = StyleSheet.create({
 box: {
 position: 'absolute',
 top: 0,
 bottom: 0,
 left: 0,
 right: 0,
 zIndex: 9999,
 },
 bg: {
 flex: 1,
 backgroundColor: 'rgba(0,0,0,0.4)',
 justifyContent: 'center',
 alignItems: 'center'
 },
 dialogBox: {
 width: 260,
 flexDirection: "column",
 backgroundColor: '#fff',
 },
 pickerBox: {
 flexDirection: "row",
 },
 btnBox: {
 flexDirection: "row",
 height: 45,
 },
 cancelBtn: {
 flex: 1,
 justifyContent: 'center',
 alignItems: 'center',
 borderColor: '#4A90E2',
 borderWidth: 1,
 },
 cancelBtnText: {
 fontSize: 15,
 color: '#4A90E2'
 },
 okBtn: {
 flex: 1,
 justifyContent: 'center',
 alignItems: 'center',
 backgroundColor: '#4A90E2',
 },
 okBtnText: {
 fontSize: 15,
 color: '#fff'
 },
})

export default Pickers

热心网友 时间:2022-05-14 16:32

React native封装原生UI组件的过程其实相当简单,见我博客Android React Native使用原生UI组件,然后如果你要使用原生模块,则参考这篇文章
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
打印机硒鼓安装方法及步骤 如何安装新硒鼓? 我现在很困惑该不该和女友继续发展下去 电脑上字体怎么安装方法简单易行的字体安装步骤及技巧 网页字体显示不出.怎么办? 如何添加电脑上没有的字体解决电脑字体限制增加字体选择多样性_百度知 ... 不有效字体文件 电脑字体识别不了 梦见身上煤炭黑的长辈给我钥匙的预兆 株洲最值得一去的古镇 心理咨询师在校生可以考吗?要多少钱考一个 考心理咨询师需要多少钱?哪种方式费用最低 要考心理咨询师的,报名费大概多少 长沙做金融靠谱吗? 有朋友介绍做金融,钱投资在别人的银行卡里面靠谱吗? 做金融类农产品的工作靠谱吗 vivo,OPPO,苹果,能不能下载华为穿戴? 术后,吃什么补血最好最快 手术补血的食物有哪些 2007CAD无意把经典模式窗口删除了,怎样操作才能恢复? 无锡医保卡,报销 无锡用社保卡买商业险 关于全国计算机二级中的线性链表,二叉树,数据库基础,软件开发的知识点 自考专科和自考本科能在上海进入大公司吗? 上海地区自考规矩 上海自考需要满足什么要求 超薄智能手机有哪些? 不超多1厘米的超薄智能手机有哪些 推荐几款超薄智能手机 静脉曲张可以运动吗 潮州人做红粿用的那种色剂是什么成分? 洗面奶成分里有着色剂好吗? 酶抑制测农药残留试剂的缓冲液(提取液)、底物、显色剂都是什么成分啊? 着色剂的化学成分 氨氮显色剂的主要成分? 沉甸甸一词中,第二个“甸”读几声 沉甸甸的甸拼音 &quot;沉甸甸&quot;到底读什么呀? 查现代汉语词典,上面写的是沉甸甸(4),说口语中也读一声,到底是什么? 沉甸甸中的读音是什么? 旋转的读音是什么? 西安哪有卖栀子花的? 重庆西彭镇到铜梁县东城街道办事处怎么坐车?? 如何封装React-Native的Modal 狗蚤用什么药杀死 有什么方法可以除死家里的狗蚤 消灭狗蚤的办法 用什么药能杀死狗蚤,跳蚤,用宝力刹有用吗? 杀狗蚤有什么好方法 治疗狗蚤的最佳办法? 用点什么药可以杀死狗身上的跳蚤 用什么药或药水给小狗洗澡可以杀死小狗身上的跳蚤?