一 Demo三端效果图

Screenshot_20200525_124217_com.tarodemo.jpg image.png Screenshot_20200525_110542_com.alibaba.android.rimet.jpg
RN端 小程序端 h5端


仅实现了滑动到底部自动加载更多的长列表页作为演示功能
**

二 整体布局

2.1 标题栏

为了达到原生App的沉浸式效果,需要根据平台类型隐藏除小程序外其他平台的默认标题栏,在入口文件中配置:

  1. config = {
  2. window: {
  3. //标题栏背景色
  4. navigationBarBackgroundColor:'#ffffff',
  5. //标题栏文本颜色
  6. navigationBarTextStyle:'black',
  7. //隐藏两端的默认标题栏,此时可以自定义标题栏
  8. navigationStyle: process.env.TARO_ENV === 'weapp' ?'default':'custom'
  9. }
  10. }

2.2 固定搜索条和tab切换条

  1. render () {
  2. ...
  3. return (
  4. <View className='page'>
  5. <SearchBar/>
  6. <TabBar tabs={tabs} onTabClick={this.onTabClick}/>
  7. <List topDist={170} datas={datas} />
  8. </View>
  9. )
  10. }

页面根布局设置相对定位,搜索条和tab切换条设置绝对定位于页面顶部。
搜索条和tab切换条高度写死,两者高度和作为属性传入列表页,通过动态样式来设置列表页距离顶部的距离

2.3 列表页

ScrollView 标签来实现列表的滚动,高度必须显示的设置,RN端的长列表必须使用renderItem属性,因此利用文件条件编译,单独创建rn的列表组件文件,其核心代码如下:

  1. <ScrollView
  2. className={scrollWarp}
  3. style={{height}}
  4. data={datas}
  5. renderItem={({item,index}) =>
  6. <View className={'itemWrap'}>
  7. <Item item={item} index={index} key={index} />
  8. ...
  9. </View>
  10. }
  11. scrollY
  12. keyExtractor = {(item,index) => `${index}`}
  13. onScrollToUpper={this.onScrollToUpper.bind(this)}
  14. onScrollToLower={this.onScrollToLower.bind(this)}
  15. />

onScrollToLower 会触发加载更多的请求

2.4 视频封面和播放按钮

背景封面使用View相对定位+Image绝对定位实现
播放按钮居中利用一个和封面一样大小的透明蒙层作为容器,设置flex布局并设置内部子标签的垂直水平居中来实现

三 数据流

3.1 关注和取消关注

将mobx的数据模型注入到Item组件,以便于操作数据:

  1. @inject('indexMod')
  2. @observer
  3. export default class Item extends PureComponent

点击关注或者已关注按钮时,调用mobx数据模型中的方法,修改数据

  1. onFollowClick(index,active,name) {
  2. const {indexMod} = this.props
  3. indexMod.setFollowState(index, !active)
  4. Taro.showToast({title: (active?'取消关注':'已关注')+name ,icon:'none'});
  5. }

在mobx数据模型中根据id找到列表子数据并修改

  1. setFollowState(index, isFollow) {
  2. this.list = this.list.map(item => {
  3. if (item.id === this.currentId) {
  4. item.res[index].data.author.follow.followed = isFollow
  5. }
  6. return item
  7. })
  8. }

3.2 加载更多

找到对应tab的数组,进行concat操作,将请求到的更多数据加到原来的数组中

  1. if (isLoadMore) {//加载更多
  2. this.list = this.list.map(item => {
  3. if (item.id === this.currentId) {//找到后更新数据
  4. item.res = item.res.concat(res)
  5. }
  6. return item
  7. })
  8. } else {
  9. this.list.push({id, res})
  10. }

3.3 Tab切换

tab切换时,没有缓存数据的列表需要请求后台,然后进行内存缓存,减少tab重复切换时的网络请求

  1. onTabClick = (tab) => {
  2. const { indexMod } = this.props
  3. indexMod.currentId = tab.id
  4. //判断当前tab的列表数据是否被缓存过
  5. let hasCached = false
  6. indexMod.list.map(data => {
  7. if(data.id === tab.id){
  8. hasCached = true
  9. }
  10. })
  11. //如果没有缓存当前tab数据,就去请求服务器
  12. if(!hasCached){
  13. indexMod.getDatas(tab.id)
  14. }
  15. indexMod.onTabClick(tab.id)
  16. }