seho20001123
seho20001123
  • 发布:2019-05-29 14:28
  • 更新:2020-10-15 11:30
  • 阅读:5223

【scroll-view】优化求建议,APP滑动抖动,不知道哪里出现的问题,求告知

分类:uni-app

先说场景:类似于电影选座的场景,日期滑动 - 》 顶部的区域滑动 -》 下方的展示区域,三者皆可滑动;,下图预览效果;

三个区域都是可以滑动,日期的滑动可以带动右边的列表区域上下滑动;
上面的左右的滑动也可以带着下面的区域滑动;
区域的上下左右可以同时带着日期和区域上下左右滑动;

遇到的问题;H5滑动没有卡顿,APP就有卡顿和抖动;抖动很明显;

代码思路:设置left变量和top变量;
只要滑动列表,就把列表项和区域项往左;
往下滑同理;
等于说每滑动一次,上下左右滑动,都要赋值本地变量,然后靠这个本地变量来绑定在scroll-view上做设置;

代码:

  <!-- 传递demo对象 -->  
  <view class="box">  
    <!-- 宴会厅名称 -->  
    <view class="top">  
      <scroll-view  
        scroll-x="true"  
        @scroll="scrollOn"  
        :scroll-left="scrollPosition"  
        scroll-with-animation="true"  
      >  
        <view class="tab" :style="{width:navWidth+'px'}">  
          <!-- 列表 -->  
          <view class="item iconfont" v-for="(tab,index) in list" :key="index">  
            {{tab.area_name}}  
            <!-- <span @click="deleteItem(index)" v-if="deleteShow">&#xe615;</span> -->  
          </view>  
        </view>  
      </scroll-view>  
    </view>  
    <!-- 日期列表 -->  
    <view class="left">  
      <scroll-view  
        :style="{height:windowHeight - 235 +'px'}"  
        scroll-y="true"  
        @scroll="ScrollTopOn"  
        :scroll-top="scrollTop"  
      >  
        <!-- 撑高度的白块 -->  
        <view class="date" style="height:35px;"></view>  
        <!-- 日期列表 -->  
        <view class="date" v-for="(item,index) in num" :key="index">{{month}}-{{index+1}}</view>  
      </scroll-view>  
    </view>  
    <!-- 列表 -->  
    <scroll-view  
      style="height:600px;"  
      scroll-x="true"  
      scroll-y="true"  
      @scroll="scrollOn"  
      :scroll-left="scrollPosition"  
      :scroll-top="scrollTop"  
      :style="{height:windowHeight - 235 +'px'}"  
    >  
      <view class="itemList" :style="{width:hotelWidth+'px'}">  
        <!-- 每一个li都是一列 -->  
        <view class="item" v-for="(main,mainIndex) in overList" :key="mainIndex">  
          <view  
            class="sonList"  
            :class="{active: son.y == mainIndex && son.x == index}"  
            v-for="(hotel,index) in main.revel_info"  
            :key="index"  
            @click="handelClickBuy(hotel,index,mainIndex)"  
          >  
            <view  
              class="topSon"  
              :class="{red:hotel.lunch_status == 2,purple:hotel.lunch_status == 1}"  
              v-if="hotel.revel_time != null && hotel.revel_time == index+1"  
            >午</view>  
            <view  
              class="bottomSon"  
              :class="{red:hotel.dinner_status == 2,purple:hotel.dinner_status == 1}"  
              v-if="hotel.revel_time != null && hotel.revel_time == index+1"  
            >晚</view>  
            <!-- <div class="allSon" v-if="hotel.dinner_status == 0 &&"></div> -->  
          </view>  
        </view>  
      </view>  
    </scroll-view>  
  </view>  
</template>  
<script>  
export default {  
  data() {  
    return {  
      // 点击son的x,y轴坐标  
      son: {  
        x: -1,  
        y: -1  
      },  
      num: 30,  
      navNum: 12,  
      navWidth: 0,  
      hotelWidth: 0,  
      scrollPosition: null,  
      scrollTop: null,  
      windowHeight: null,  
      deleteShow: true,  
      // 处理后的后端数据  
      overList: []  
    };  
  },  
  async mounted() {  
    // 返回附给nav尺寸  
    this.loadNavWidth();  
    // 计算年月  
    await this.computedYear();  
    // 对后端返回的数据做一层包装,使之能在模板中有着月份的长度正常渲染  
    this.overReturnList();  
    // 获取窗口高度  
    this.windowHeight = uni.getSystemInfoSync().screenHeight;  
    // 判断列表长度,设置删除键是否显示  
    if (this.list.length == 1) {  
      this.deleteShow = false;  
      return;  
    }  
  },  
  methods: {  
    // 点击看板列表  
    handelClickBuy(item, index, mIndex) {  
      // 拿到mIndex:通过minx拿到是第几个宴会厅  
      this.son.y = mIndex;  
      this.son.x = index;  
      // 向上提交  
      this.$emit("clickView", this.son);  
    },  
    // 删除一列  
    deleteItem(index) {  
      if (this.list.length == 2) {  
        this.deleteShow = false;  
        return;  
      }  
      this.overList.splice(index, 1);  
      this.list.splice(index, 1);  
      // 对宽度进行一个减少 navWidth && hotelWidth  
      this.navWidth = this.navWidth - 105;  
      this.hotelWidth = this.hotelWidth - 100; // 减去它们每一项的宽度  
    },  
    // 计算日期列表和view列表的上下滑动统一  
    ScrollTopOn(e) {  
      this.scrollTop = e.detail.scrollTop;  
    },  
    // 计算年月  
    computedYear() {  
      // 判断是否是闰年  
      if (  
        (this.year % 4 == 0 && this.year % 100 != 0) ||  
        this.year % 400 == 0  
      ) {  
        // 闰年 2月29天  
        if ((this.month = 2)) {  
          this.num = 29;  
          this.overReturnList();  
          return;  
        }  
      } else {  
        // 平年  
        if (this.month == 2) {  
          this.num = 28;  
          this.overReturnList();  
          return;  
        }  
      }  
      if (  
        this.month == 1 ||  
        this.month == 3 ||  
        this.month == 5 ||  
        this.month == 7 ||  
        this.month == 8 ||  
        this.month == 10 ||  
        this.month == 12  
      ) {  
        this.num = 31;  
        this.overReturnList();  
        return;  
      } else {  
        this.num = 30;  
        this.overReturnList();  
        return;  
      }  
    },  
    // 处理后端返回数据  
    overReturnList() {  
      uni.showLoading({  
        title: "解析看板数据中..."  
      });  
      // 遍历原数组个数  
      var overList = [];  
      var sliceList = JSON.parse(JSON.stringify(this.list)); // 深拷贝  
      if (sliceList.length == 0) {  
        return;  
      }  
      sliceList.map(v => {  
        // 构建arrayInfo  
        let arrayInfo = [];  
        // 默认添加的对象 (全部为空)  
        let dayObj = {  
          id: 1, // 有待商议  
          revel_time: null,  
          lunch_status: 0,  
          dinner_status: 0  
        };  
        // 出现的天数arr  
        let arr = [];  
        // 循环info的天数组成一个数组  
        for (let key in v.revel_info) {  
          // 序列化之后的字符串是 2019-04-09T02:20:58.601Z 需要拿到09这个天数  
          let showIndex = v.revel_info[key].revel_time.indexOf("-", 7);  
          // 切割字符串拿到天数,如果开头为0则去掉0,不为0直接被添加到数组中  
          var str = v.revel_info[key].revel_time.substr(showIndex + 1, 2);  
          if (str[0] != 0) {  
            arr.push(str);  
          } else {  
            arr.push(str[1]); // 添加天数  
          }  
        }  
        // 通过当前月份的天数来循环添加  
        for (let key = 0; key < this.num; key++) {  
          // 查询arr中的天数是否与当前循环的天数匹配  
          let num = arr.indexOf((key + 1).toString()); // 转成字符串进行查询  
          if (num != -1) {  
            // 如果当前循环的天数在arr中被找到,就不用添加空对象到数组中  
            v.revel_info[num].revel_time = v.revel_info[num].revel_time.substr(  
              v.revel_info[num].revel_time.indexOf("-", 7) + 1,  
              2  
            );  
            // 以上代码参考124行逻辑,就是切割字符串把天数附给revel_time在模板中展示出来  
            arrayInfo.push(v.revel_info[num]);  
          } else {  
            arrayInfo.push(dayObj); // 填充数组成功  
          }  
        }  
        // 拿到全部的对象,对象中的info就是我们要的内容  
        let obj = {  
          area_id: v.area_id,  
          area_name: v.area_name,  
          revel_info: arrayInfo  
        };  
        overList.push(obj);  
      });  
      this.overList = overList;  
      uni.hideLoading();  
    },  
    scrollOn(e) {  
      this.scrollPosition = e.detail.scrollLeft;  
      console.log(e.detail.scrollLeft);  
      if (e.detail.scrollTop == 0) {  
        return;  
      }  
      this.scrollTop = e.detail.scrollTop;  
    },  
    loadNavWidth() {  
      // 获取长度  
      this.navWidth = (85 * this.list.length) + 60;  
      // this.navWidth = `${navNum + 40}`; // nav与下方滑块兼容长度(60px不精准,但是能和下面滑块进行大致同步)  
      this.hotelWidth = (80 * this.list.length) + 40;  
      // this.hotelWidth = `${num + 10}`;  
    }  
  },  
  watch: {  
    year() {  
      this.computedYear();  
    },  
    month() {  
      this.computedYear();  
    },  
    list() {  
      this.loadNavWidth();  
      // 重新加载  
      this.overReturnList();  
    }  
  },  
  props: {  
    list: {  
      type: Array,  
      default: () => {  
        return [];  
      }  
    },  
    year: {  
      type: Number,  
      default: () => {  
        return 2019;  
      }  
    },  
    month: {  
      type: Number,  
      default: () => {  
        return 1;  
      }  
    },  
    viewFiexedScroll: {  
      typr: Boolean,  
      default: () => {  
        return false;  
      }  
    }  
  }  
};  
</script>  
2019-05-29 14:28 负责人:无 分享
已邀请:
Kuo

Kuo - Java? No~ just coffee~~

遇到相同的问题了,两个scroll-view联动,iOS上就会抖动

  • Kuo

    我这边发现的问题是,滚动的同时设置了scrollTop导致的

    2019-07-08 16:22

  • 2019

    回复 Kuo: 请问怎样解决这个问题?我也是这种情况,设置了scrollTop。

    2020-05-07 18:12

  • 3***@qq.com

    回复 huawinner: 请问怎样解决这个问题?我也是这种情况,设置了scrollTop

    2020-10-28 15:41

  • 7***@qq.com

    回复 Kuo: 谢谢亲

    2021-04-17 14:39

DCloud_UNI_GSQ

DCloud_UNI_GSQ

请提供一个复现问题的简单示例工程

  • 即时通讯开发

    我的也有这个问题,去掉这个就好了 加上文档上的那个属性也不行

    2020-05-13 09:43

DCloud_UNI_GSQ

DCloud_UNI_GSQ

不要把滚动事件获取的值直接设置回scrollTop,如果是为了解决设置scrollTop为相同的值观测不到的问题可以参考文档。或者设置的时候加一个防抖函数。

即时通讯开发

即时通讯开发

你滚动的时候有加css3动画吗 我的去掉css3动画就不抖动了

3***@qq.com

3***@qq.com

我现在跟楼主的出现一样的问题,我目前都只有像官方示例一样采用old来获取值,然后定时赋值给滑动变量,并且时长改长点才能让抖动的出现概率变低。谁有没有解决方案,或者@DCloud_UNI_GSQ,可有防抖函数示例?

8***@qq.com

8***@qq.com - lisp

iOS上,上滑抖动

李老八

李老八

我的横向滚动解决了这个问题,我是在 @scroll=“ scroll”方法中不赋值滚动的值e.detail.scrollLeft;

该问题目前已经被锁定, 无法添加新回复