Taro小程序开发组件中填过的坑

1,235 阅读5分钟

一、taro/components组件中的swiper概率性出现空白页

问题描述:移动端使用taro/components中的swiper组件进行轮播图的展示,如果管理后台删除或者下架一个banner图片,此时移动端会出现白屏的情况,并且swiper组件不轮播。

原因分析:当管理后台删除一个图片或者是下架一个图片的时候此时移动端拿到的数据已经更新了,但是swiper组件中的current属性并未及时的更新,如果current当前的属性恰好等于管理台删除(或下架)的轮播图在原数组中的索引,此时会导致current找不到对应索引的banner图(由于数据已经更新了,current对应索引的banner图已删除或下架),就会出现轮播图空白页的情况,并且轮播动画停止了。

解决方法:只需要在监听banner变化的时候动态的更新current属性即可。

关键代码示例:

    import { useEffect, useState } from "react";
    import { Swiper, SwiperItem, Image } from "@tarojs/components";
    
    export default fucntion SwiperComponent({
        bannerList
    }){
        const [currentSwiperItem, setCurrentSwiperItem] = useState(0); // 默认current的值
        // 监听bannerList的变化
        useEffect(() => {
            setCurrentSwiperItem(0); //默认设置为第一个banner页
            // setCurrentSwiper(bannerList.length - 1); // 或者是默认设置为最后一个banner
        }, [bannerList]);
        
        
        returen bannerList.length > 0? (
           <Swiper
            autoPaly
            indicatorColor='#999'  
            indicatorActiveColor='#333'  
            vertical  
            circular  
            indicatorDots
            current={currentSwiperItem} {/** 动态绑定current的值 */}
            onChange={(e) => {
                const { current } = e?.detail;
                // 获取banner的id
                const currentBannerId = bannerList[current].id;
                // 请求后台进行曝光量的计算
                ...
            }}
           >
               {
                   bannerList.map(banner => ( 
                       <SwiperItem key={banner?.id}>
                           <Image src={banner?.imageUrl} />
                       </SwiperItem>
                   ))
               }
           </Swiper>
       ): <></>; 
    }

【重点注意】当在Swiper组件中设置了current的属性时,就不能设置currentItemId的属性,即使是在SwiperItem中设置itemId={banner?.id}也不可以,具体可参照:https://taro-docs.jd.com/docs/components/viewContainer/swiper。中的Swiper属性说明。

【额外拓展】如果需要计算banner图的曝光量和点击量,此时如果需求是根据banner的id进行上报的话,由于在Swiper中不能设置currentItemId,所以需要监听onChange事件通过current索引拿到banner的id。

二、taro/components组件中的输入类表单组件【Input、TextArea】等字数限制在taro3.5.9以下版本无效无效

问题描述:在taro3.5.7版本中使用Input或TextArea组件的maxlength属性限制字数无效,不管设置的maxlength是多少,最终在界面渲染出来的都是maxlength=140。最大只支持输入140个字符。

原因分析:这是由于小程序中taro-plugin-html包处理的问题,具体的原因分析可参照:https://github.com/jdf2e/nutui-react/issues/442。

解决方法:升级taro【以及所有与taro相关的包】版本到3.5.9即可。

三、@nutui/nutui-react-taro低版本下的Uploader组件上传图片的bug

问题描述:在使用低版本的@nutui/nutui-react-taro的uploader组件中进行图片删除时,会出现同时删除多个图片的情况,即使在删除时不用uid进行标识也是一样的。

原因分析:在使用低版本的@nutui/nutui-react-taro的uploader组件时,由于支持图片的批量上传(只有当1.4.8或以上版本才增加了multiple属性,来定制化文件的批量上传是否支持),所以有可能会出现两个或两个以上的文件的唯一标识uid一直的情况,这是因为uid默认的创建方式是Date().getTime().toString()来创建,所以很有可能出现在批量上传是多个文件的uid相同的情况,此时在uploader组件中进行图片删除时会出现同时删除多个图片的情况,即使在删除时不用uid进行标识也是一样的。

解决方法:【1】将@nutui/nutui-react-taro升级到1.4.8或以上版本,来设置文件不能批量上传;【2】在onChange方法中拿到文件的数组,使用uuid作为文件的uid值,确保每个文件uid的唯一性。

关键代码示例:

    import React, { PureComponent } from "react";
    import { Uploader } from "@nutui/nutui-react-taro";
    import { v4 as uuid } from "uuid";
    
    export default class UploaderComponent extends PureComponent{
        constructor(props){
            super(props);
            this.state = { 
                ...
                defaultFileList: [],
                ...
            };
            this.handleChangeFile = this.handleChangeFile.bind(this);
            this.handleRemove = this.handleRemove.bind(this);
        }
        
        function handleChangeFile({ fileList }){
            fileList.forEach((file: FileItem) => {
                file.uid = uuid();
            });
            ...
        }
        
        function handleRemove(file: FileItem){
            this.setState(defaultFileList.filter(fileItem => fileItem.uid !== file.uid));
        }
        
        render(){
            return (
                <>
                    ...
                    <Uploader
                        defaultFileList={defaultFileList}
                        mutliple={false} // 1.4.8+版本的批量上传属性
                        onChange={this.handleChangeFile}
                        onRemove={this.handleRemove}
                    />
                    ...
                </>
            );
        }
    }

四、@nutui/nutui-react-taro组件库中使用公告栏组件的问题

问题描述:nutui-react-taro组件库中的noticebar组件的垂直轮播滚动只适用于一次展示一条信息,在碰到公告栏的高度可以一次同时展示两条公告的条件或需求下,此时noticebar就无法适用了。此时需要自定义公告栏组件实现。

关键代码实例

//index.tsx
import React, { Component } from 'react'
import styles from './index.less';

export default class NoticeBar extends Component<any, any> {
  constructor(props) {
    super(props);
    this.state = {animate: false}
  }

  componentDidMount() {
    const { duration } = this.props; // duration表示间隔的时间
    setInterval(() => {
      this.setState({
        animate: true
      })
      this.changeAnim();
    }, duration);
  }

  //在setInterval执行中,会调用该函数,在内部会设置一个一次性的定时器,每次都会将数组的第一个元素添加到数组的最后,并且将数组的第一个元素删除,
  changeAnim = () => {
    const { list } = this.props;
    setTimeout(() => {
      list.push(list[0]);
      list.shift();
      this.setState({animate: false});
    }, 500)
  }


  render() {
    const { animate } = this.state;
    const { list, rightIcon } = this.props;
    return (
      <div className={styles.scrollPage}>
        <div className={styles.scrollWrapper}>
          {/*//列表根据animate 来判断是否添加anim类样式*/}
          <view className={animate ? [styles.viewContainer, styles.anim].join(" ") : styles.viewContainer}>
            {
              list.map((item) => {
                return (
                  <view className={styles.listItem} key={item.id}>
                    {
                      item.title
                      // item.map(((i, index) => (
                      //   <view className={styles.noticeBarItem} style={index >= 1? {marginTop: "-8px"}: {}} key={i.key}>{i.text}</view>
                      // )))
                    }
                  </view>
                );
              })
            }
          </view>
        </div>
        { rightIcon }
      </div>
    )
  }
}

// index.less
.scrollPage {
  display: flex;
  align-items: center;
  margin-left: 8px;
  height: 52px;

  .scrollWrapper {
    position: relative;
    overflow: hidden;
    height: 90%;
    width: 225px;
    .viewContainer {
      position: absolute;
      top: 0;
      left: 0;
      .listItem {
        max-width: 225px;
        //height: 52px;
        //height: 26px;
        line-height: 24px;
        //display: flex;
        //flex-direction: column;
        //justify-content: center;

        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;

        font-weight: 400;
        font-size: 14px;
        color: #363A44;
        .noticeBarItem{
          font-weight: 400;
          font-size: 14px;
          color: #363A44;

          width: 100%;
          height: 100%;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
        }
      }
    }
  }
}

//动画
.anim {
  transition: all 1s ease;
  margin-top: -24px;
}

【注意】此组件是适用于公告栏垂直滚动,且一次展示两条的情况和需求下才适用,普通的公告栏直接用组件库中的即可。