解决uniapp列表快速滑动页面数据空白问题

前言:

近期UNIAPP架构开发小程序时,项目收尾整体流程测试发现,Swiper滑动嵌套Scroll列表加载更多时候,如果用户快速滑动列表加载会导致页面空白或者直接卡死,官方文档不建议使用scroll滚动趋势线长列表加载,swiper中不用scroll,高度计算不准确,list又不太好触发滑到底部事件,反反复复各种优化各种改,最终在z-paging自定义中把这个问题处理掉了,效果跟需求几乎满足百分之九十五以上。↓↓↓↓↓↓ 如下效果

上滑加载下拉刷新

 下拉刷新上滑加载组件

【z-paging下拉刷新、上拉加载】高性能,全平台兼容。支持虚拟列表,支持nvue、vue3 - DCloud 插件市场 超简单、低耦合!使用wxs+renderjs实现。支持长列表优化,支持自定义下拉刷新、上拉加载更多,支持自动管理空数据图、点击返回顶部,支持聊天分页、本地分页,支持国际化等100+项配置https://ext.dcloud.net.cn/plugin?id=3935

<!-- 在这个文件对每个tab对应的列表进行渲染 -->
<template>
  <view class="content">
    <!-- 此处为了让reload时不自动滚动到顶部,需要设置auto-clean-list-when-reload和auto-scroll-to-top-when-reload为false,即在reload时关闭自动清空数组和自动滚动到顶部 -->
    <z-paging
      ref="paging"
      v-model="dataList"
      @query="queryList"
      :fixed="false"
       empty-view-text="抱歉,暂时还没有相关数据!"
      :auto="false"
    >
      <!-- <view class="banner-view" style="height: 260rpx"> </view> -->
      <view class="item" v-for="(item, index) in dataList" :key="index">
        <view class="ul">
          <!--所有涉及到文章的  有2个样式  1个是带缩略图的  1个是不带缩略图的-->
          <!--带缩略图的-->
          <view>
            <view
              class="li"
              @click="goArticleInfo(item)"
              v-if="item.content_row.has_thumb == 1"
            >
              <view class="font">
                <text class="p">{
   
   { item.content_row.title }}</text>
                <text class="span">{
   
   { item.content_row.created }}</text>
              </view>
              <view class="pic">
                <image :src="item.content_row.thumb" mode="widthFix"></image>
              </view>
            </view>
            <view class="li" @click="goArticleInfo(item)" v-else>
              <!--不带缩略图的-->
              <view class="fontwenzi">
                <text class="title">{
   
   { item.content_row.title }}</text>
                <text class="info">{
   
   {
                  item.content_row.description.replace(/\s+/g, "")
                }}</text>
                <text class="span">{
   
   { item.content_row.created }}</text>
              </view>
            </view>
          </view>
        </view>
      </view>
      <!--  -->
    </z-paging>
  </view>
</template>
<script>
export default {
  data() {
    return {
      //v-model绑定的这个变量不要在分页请求结束中自己赋值!!!
      dataList: [],
      firstLoaded: false,
    };
  },
  props: {
    //当前组件的index,也就是当前组件是swiper中的第几个
    tabIndex: {
      type: Number,
      default: function () {
        return 0;
      },
    },
    // 类别id
    typeid: {
      type: Number,
      default: function () {
        return 0;
      },
    },
    //当前swiper切换到第几个index
    currentIndex: {
      type: Number,
      default: function () {
        return 0;
      },
    },
  },
  watch: {
    currentIndex: {
      handler(newVal) {
        if (newVal === this.tabIndex) {
          //懒加载,当滑动到当前的item时,才去加载
          if (!this.firstLoaded) {
            setTimeout(() => {
              this.$refs.paging.reload();
            }, 100);
          }
        }
      },
      immediate: true,
    },
  },
  methods: {
	  /**
	   * 选中事件
	   * @param {*} item 
	   */
	  goArticleInfo(item){
		  this.$emit("goArticleInfo",item);
	  },
	  /**
	   * 
	   * @param {*} page 
	   * @param {*} pageSize 
	   */
    queryList(page, pageSize) {
      //组件加载时会自动触发此方法,因此默认页面加载时会自动触发,无需手动调用
      //这里的pageNo和pageSize会自动计算好,直接传给服务器即可
      //模拟请求服务器获取分页数据,请替换成自己的网络请求
      var that = this;
      that
        .$http(
          "/article/?page=" +
            page +
            "&pageSize=" +
            pageSize +
            "&typeid=" +
            this.typeid,
          "POST",
          {},
          {}
        )
        .then((res) => {
          if (res.code == 200) {
            that.classify_list = res.classify_list;
            that.classify_list.unshift({
              id: 0,
              name: "全部",
            });
            setTimeout(function () {
              uni.hideLoading();
            }, 800);
            //将请求的结果数组传递给z-paging
            this.$refs.paging.complete(res.list);
          } else if (res.code == 400) {
            this.$refs.paging.complete(res.list);
          } else {
            uni.showToast({
              title: "接口异常!",
              icon: "none",
              duration: 2000,
            });
          }
        });
    },
  },
};
</script>

<style>
/* 注意:父节点需要固定高度,z-paging的height:100%才会生效 */
.content {
  height: 100%;
    padding-top: 280rpx;
}

.item {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0rpx 30rpx;
}

.item-detail {
  padding: 5rpx 15rpx;
  border-radius: 10rpx;
  font-size: 28rpx;
  color: white;
  background-color: #007aff;
}

.item-line {
  position: absolute;
  bottom: 0rpx;
  left: 0rpx;
  height: 1px;
  width: 100%;
  background-color: #eeeeee;
}

/* css */

.content {
  overflow: hidden;
  width: 100%;
}

.closedbox image {
  width: 20rpx;
}

.content .loding {
  overflow: hidden;
  height: 68rpx;
  background: #f8f8f8;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.content .loding image {
  width: 24rpx;
  border-radius: 50%;
  animation: turn 2s linear infinite;
}

.content .loding .span {
  font-size: 22rpx;
  color: #999999;
  margin-left: 10rpx;
}

.fadeins {
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.5);
  position: fixed;
  left: 0;
  top: 0;
  z-index: 999;
}

.select_box {
  width: 100%;
  height: 1rpx;
  border-top: 1px solid #efefef;
  display: flex;
  align-items: center;
  /* // z-index: 9999; */
  background: #fff;
  position: relative;
}

.main_science {
  overflow: hidden;
  padding: 0rpx 30rpx 0 30rpx;
}

.ul {
  overflow: hidden;
}

.ul .li:last-child {
  border: none;
}

.ul .li {
  overflow: hidden;
  display: flex;
  padding: 40rpx 0;
  box-sizing: border-box;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  border-bottom: 1px solid #f1f1f1 !important;
}

.ul .li .font {
  overflow: hidden;
  width: 365rpx;
}

.ul .li .font .p {
  font-size: 32rpx;
  color: #333333;
  line-height: 42rpx;
  display: block;
  margin-bottom: 34rpx;
}

.ul .li .font .span {
  display: block;
  font-size: 26rpx;
  color: #9a9ca0;
}

.ul .li .fontwenzi {
  overflow: hidden;
  width: 100%;
}

.ul .li .fontwenzi .title {
  font-size: 33rpx;
  color: #333333;
  line-height: 42rpx;
  display: block;
  margin-bottom: 34rpx;
}

.ul .li .fontwenzi .info {
  font-size: 26rpx;
  color: #8c8c8c;
  line-height: 42rpx;
  display: block;
  margin-bottom: 34rpx;
}

.ul .li .fontwenzi .span {
  display: block;
  font-size: 26rpx;
  color: #9a9ca0;
}

.ul .li .pic {
  overflow: hidden;
  width: 260rpx;
  border-radius: 20rpx;
}

.ul .li .pic image {
  display: block;
  width: 100%;
}
</style>

页面中使用调用

<!-- 滑动切换选项卡演示(标准写法) -->
<template>
  <!-- 使用z-paging-swiper为根节点可以免计算高度 -->
  <view>
    <!-- 吸顶 -->
    <u-sticky>
      <!-- 只能有一个根元素 -->
      <view class="sticky" style="background-color: #fff !important">
        <uni-nav-bar
          statusBar
          leftIcon="back"
          @clickLeft="goback"
          fixed="true"
          title="医药文章科普"
          height="50"
          :border="false"
        >
        </uni-nav-bar>
        <view class="sroll_list">
          <!--  show-scrollbar="true" -->
          <scroll-view
            scroll-x="true"
            enable-flex="true"
            :scroll-into-view="'tab' + navbarindex"
            scroll-with-animation
          >
            <view
              class="li"
              :class="navbarindex == index ? 'on' : ''"
              v-for="(item, index) in classify_list"
              :key="index"
              @click="getTab(item, index)"
              :id="'tab' + index"
            >
              {
   
   { item.name }}
            </view>
          </scroll-view>
          <view class="menu" @click="show = true">
            <image src="../../static/addicon4.png" mode="widthFix"></image>
          </view>
        </view>
      </view>
    </u-sticky>

    <view
      class="main_article_fade"
      @touchmove.stop.prevent="moveHandle"
      v-if="show"
    >
      <view class="box">
        <view class="ul">
          <view
            class="li"
            v-for="(item, index) in classify_list"
            :key="index"
            :class="navbarindex == index ? 'on' : ''"
            @click="getTab(item, index)"
            >{
   
   { item.name }}</view
          >
          <image
            @click="getDShow"
            src="../../static/icon-close.png"
            mode="widthFix"
          ></image>
        </view>
      </view>
    </view>
    <view class="select_box"></view>
    <z-paging-swiper>
      <!-- 需要固定在顶部不滚动的view放在slot="top"的view中 -->
      <!-- swiper必须设置height:100%,因为swiper有默认的高度,只有设置高度100%才可以铺满页面  -->
      <swiper
        class="swiper"
        :current="navbarindex"
        @animationfinish="animationfinish"
      >
        <swiper-item
          class="swiper-item"
          v-for="(item, index) in classify_list"
          :key="index"
        >
          <article-item
            :tabIndex="index"
            :typeid="typeid"
            @goArticleInfo="goArticleInfo"
            :currentIndex="navbarindex"
          ></article-item>
        </swiper-item>
      </swiper>
    </z-paging-swiper>
  </view>
</template>

<script>
export default {
  data() {
    return {
      typeid: 0,
      show: false,
      classify_list: [],
      navbarindex: 0, // tabs组件的current值,表示当前活动的tab选项
    };
  },
  mounted() {
    uni.showLoading({
      title: "加载中",
    });
    this.initData();
  },
  methods: {
    getDShow() {
      this.show = !this.show;
    },
    /**
     * 跳转详情
     */
    goArticleInfo(item) {
      console.log(item);
      uni.navigateTo({
        url: "/pages/article/info?id=" + item.content_row.id,
      });
    },
    goback() {
      uni.navigateBack({
        delta: 1,
      });
    },

    /**
     *根据分类获取科普文章列表
     *@param {item}当前选中标签的数据id/name
     *@param {index}当前选中标签状态索引
     *@param {show} 遮罩层状态
     */
    getTab(item, index) {
      console.log(item, index);
      this.navbarindex = index;
      this.typeid = item.id;
      this.show = false;
      uni.showLoading({
        title: "加载中",
      });
      //   //当切换tab时请调用组件的reload方法,请勿直接调用:queryList方法!!
      //   this.$refs.paging.reload();
    },
    //swiper滑动结束
    animationfinish(e) {
      let navbarindex = e.detail.current;
      console.log("e.detail.current", e.detail.current);
      this.navbarindex = e.detail.current;
      this.typeid = this.classify_list[e.detail.current].id;
      uni.showLoading({
        title: "加载中",
      });
    },
    /**
     * 初始化获取数据
     */
    initData() {
      var that = this;
      that
        .$http("接口地址" , "POST", {}, {})
        .then((res) => {
          if (res.code == 200) {
            console.log("z", res);
            that.classify_list = res.classify_list;
            that.classify_list.unshift({
              id: 0,
              name: "全部",
            });
                setTimeout(function () {
              uni.hideLoading();
            }, 800);
          } else {
            uni.showToast({
              title: "接口异常!",
              icon: "none",
              duration: 2000,
            });
          }
        });
    },
  },
};
</script>

<style>
.swiper {
  height: 100%;
}
.item {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0rpx 30rpx;
}

.item-detail {
  padding: 5rpx 15rpx;
  border-radius: 10rpx;
  font-size: 28rpx;
  color: white;
  background-color: #007aff;
}

.item-line {
  position: absolute;
  bottom: 0rpx;
  left: 0rpx;
  height: 1px;
  width: 100%;
  background-color: #eeeeee;
}

/* css */

.content {
  overflow: hidden;
  width: 100%;
}

.list_box {
  overflow: hidden;
  width: 100%;
  height: calc(100vh - 100rpx - 105rpx - 10rpx);
}

.list_box swiper {
  width: 100%;
  height: 100%;
}

.list_box scroll-view {
  width: 100%;
  height: 100%;
}

.list_box swiper-item {
  width: 100%;
  height: 100%;
}

.sroll_list {
  overflow: hidden;
  height: 105rpx;
  margin: 0 auto;
  display: flex;
  padding-bottom: 20rpx;
  align-items: center;
  background: #fff;
  position: relative;
  z-index: 9999;
  justify-content: space-between;
  width: 100%;
  padding: 0 30rpx 30rpx 30rpx;
}

.sroll_list .menu {
  width: 66rpx;
  height: 100%;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  position: relative;
}

.sroll_list .menu::after {
  content: "";
  position: absolute;
  left: -15rpx;
  top: 50%;
  transform: translateY(-50%);
  width: 15rpx;
  height: 74rpx;
  background: url(../../static/pic-menu-line.png) no-repeat;
  background-size: contain;
}

.sroll_list .menu image {
  width: 36rpx;
}

.sroll_list scroll-view {
  width: calc(100% - 66rpx);
  height: 100%;
  white-space: nowrap;
  font-size: 12px;
}

.sroll_list scroll-view .li {
  display: inline-flex;
  height: 100%;
  margin-right: 40rpx;
  position: relative;
  align-items: center;
  font-size: 32rpx;
  color: #666666;
}

.sroll_list scroll-view .li.on {
  color: #000000;
}

.sroll_list scroll-view .li.on::after {
  content: "";
  width: 29rpx;
  height: 8rpx;
  background: url(../../static/addicon2.png);
  background-size: 100% 100%;
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: 0;
}

.closedbox image {
  width: 20rpx;
}

.content .loding {
  overflow: hidden;
  height: 68rpx;
  background: #f8f8f8;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.content .loding image {
  width: 24rpx;
  border-radius: 50%;
  animation: turn 2s linear infinite;
}

.content .loding .span {
  font-size: 22rpx;
  color: #999999;
  margin-left: 10rpx;
}

.fadeins {
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.5);
  position: fixed;
  left: 0;
  top: 0;
  z-index: 999;
}

.select_box {
  width: 100%;
  height: 1rpx;
  border-top: 1px solid #efefef;
  display: flex;
  align-items: center;
  /* // z-index: 9999; */
  background: #fff;
  position: relative;
}

.main_science {
  overflow: hidden;
  padding: 0rpx 30rpx 0 30rpx;
}

.ul {
  overflow: hidden;
}

.ul .li:last-child {
  border: none;
}

.ul .li {
  overflow: hidden;
  display: flex;
  padding: 40rpx 0;
  box-sizing: border-box;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  border-bottom: 1px solid #f1f1f1 !important;
}

.ul .li .font {
  overflow: hidden;
  width: 365rpx;
}

.ul .li .font .p {
  font-size: 32rpx;
  color: #333333;
  line-height: 42rpx;
  display: block;
  margin-bottom: 34rpx;
}

.ul .li .font .span {
  display: block;
  font-size: 26rpx;
  color: #9a9ca0;
}

.ul .li .fontwenzi {
  overflow: hidden;
  width: 100%;
}

.ul .li .fontwenzi .title {
  font-size: 33rpx;
  color: #333333;
  line-height: 42rpx;
  display: block;
  margin-bottom: 34rpx;
}

.ul .li .fontwenzi .info {
  font-size: 26rpx;
  color: #8c8c8c;
  line-height: 42rpx;
  display: block;
  margin-bottom: 34rpx;
}

.ul .li .fontwenzi .span {
  display: block;
  font-size: 26rpx;
  color: #9a9ca0;
}

.ul .li .pic {
  overflow: hidden;
  width: 260rpx;
  border-radius: 20rpx;
}

.ul .li .pic image {
  display: block;
  width: 100%;
}
</style>

猜你喜欢

转载自blog.csdn.net/qq_35695041/article/details/125403709