# List 虚拟列表

大数据时候用的列表,数据大于 400

# 基础用法

<template>
  <div>
    <qinui-list
      ref="thePageNode"
      use-virtual-list
      idPrefix="store-id"
      :force-close-inner-list="true"
      @virtualListChange="onVirtualListChange"
      @query="onGetDatas"
    >
      <!-- 需要固定在顶部不滚动的view放在slot="top"的view中,如果需要跟着滚动,则不要设置slot="top" -->
      <template #top>
        <view class="header">列表总数据量:10万条</view>
        <!-- 注意!此处的z-tabs为独立的组件,可替换为第三方的tabs,若需要使用z-tabs,请在插件市场搜索z-tabs并引入,否则会报插件找不到的错误 -->
        <qinui-tabs
          :data="theTabList"
          @change="onTabsChange"
          v-model="theTabIndex"
        />
      </template>

      <!-- :id="`store-id-${item.zp_index}`"和:key="item.zp_index" 必须写,必须写!!!! -->
      <!-- store-id 和 idPrefix 一致-->
      <!-- 这里for循环的index不是数组中真实的index了,请使用item.zp_index获取真实的index -->
      <view
        class="item"
        :id="`store-id-${item.zp_index}`"
        :key="item.zp_index"
        v-for="(item, index) in theDataList"
      >
        <image
          class="item-image"
          mode="aspectFit"
          src="https://cdn.test.fanzhi.cn//images/0d/d2/70d5dc70ce6f898142cc288cf52c.jpg?x-oss-process=image/resize,w_288,h_393,m_fill/quality,q_100"
        ></image>
        <view class="item-content">
          <text class="item-title">第{{ item.title }}行</text>
          <text style="color: red; margin-left: 10rpx">虚拟列表展示</text>
          <view class="item-detail">{{ item.detail }}</view>
        </view>
        <view class="item-line"></view>
      </view>
    </qinui-list>
  </div>
</template>

<script lang="ts" setup>
  import { ref } from 'vue';
  import theAjax from '../list/ajax';

  // 虚拟列表节点
  const thePageNode = ref<any>(null);
  // tab start
  const theTabIndex = ref('tab1');
  const theTabList = ref([
    {
      label: '测试1',
      value: 'tab1',
    },
    {
      label: '测试2',
      value: 'tab2',
    },
    {
      label: '测试3',
      value: 'tab3',
    },
    {
      label: '测试4',
      value: 'tab4',
    },
  ]);

  const onTabsChange = () => {
    // 当切换tab或搜索时请调用组件的reload方法,请勿直接调用:queryList方法!!
    thePageNode.value?.reload();
  };
  // tab end

  // 虚拟列表数据 start
  const theDataList = ref<any>([]);

  // 监听虚拟列表数组改变并赋值给virtualList进行重新渲染
  const onVirtualListChange = (vList: any) => {
    theDataList.value = vList;
  };

  const onGetDatas = (thePageNo: number, thePageSize: number) => {
    // 组件加载时会自动触发此方法,因此默认页面加载时会自动触发,无需手动调用
    // 这里的 thePageNo 和 thePageSize 会自动计算好,直接传给服务器即可
    // 模拟请求服务器获取分页数据,请替换成自己的网络请求
    const theParams = {
      pageNo: thePageNo,
      pageSize: thePageSize,
      type: theTabIndex.value,
    };
    theAjax
      .queryListLong(theParams)
      .then((theRes: any) => {
        // 将请求的结果数组传递给 qinui-list
        thePageNode.value.complete(theRes.data.list);
      })
      .catch(() => {
        // 如果请求失败写 thePageNode.value.complete(false);
        // 注意,每次都需要在catch中写这句话很麻烦, qinui-list 提供了方案可以全局统一处理
        // 在底层的网络请求抛出异常时,写 qin.$emit('qinui-list-error-emit'); 即可
        thePageNode.value.complete(false);
      });
  };
  // 虚拟列表数据 end
</script>

<style>
  /* 示例样式 start */
  .item {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 20rpx 30rpx;
  }

  .item-content {
    flex: 1;
    margin-left: 20rpx;
  }

  .header {
    background-color: red;
    font-size: 24rpx;
    text-align: center;
    padding: 20rpx 0rpx;
    color: white;
  }

  .item-image {
    height: 150rpx;
    width: 150rpx;
    background-color: #eeeeee;
    border-radius: 10rpx;
  }

  .item-title {
    background-color: red;
    color: white;
    font-size: 26rpx;
    border-radius: 5rpx;
    padding: 5rpx 10rpx;
  }

  .item-detail {
    margin-top: 10rpx;
    border-radius: 10rpx;
    font-size: 28rpx;
    color: #aaaaaa;
    word-break: break-all;
  }

  .item-line {
    position: absolute;
    bottom: 0rpx;
    left: 0rpx;
    height: 1px;
    width: 100%;
    background-color: #eeeeee;
  }
  /* 示例样式 end */
</style>

# 悬停用法

<template>
  <div>
    <qinui-list
      ref="thePageNode"
      use-virtual-list
      :force-close-inner-list="true"
      @virtualListChange="onVirtualListChange"
      @query="onGetDatas"
    >
      <view class="banner-view" style="height: 250rpx">
        <view style="font-size: 40rpx; font-weight: 700">这是一个banner</view>
        <view style="font-size: 24rpx; margin-top: 5rpx"
          >下方tab滚动时可吸附在顶部</view
        >
      </view>
      <qinui-affix>
        <qinui-tabs
          :data="theTabList"
          @change="onTabsChange"
          v-model="theTabIndex"
        />
      </qinui-affix>
      <!-- :id="`zp-id-${item.zp_index}`"和:key="item.zp_index" 必须写,必须写!!!! -->
      <!-- 这里for循环的index不是数组中真实的index了,请使用item.zp_index获取真实的index -->
      <view
        class="item"
        :id="`zp-id-${item.zp_index}`"
        :key="item.zp_index"
        v-for="(item, index) in theDataList"
      >
        <image
          class="item-image"
          mode="aspectFit"
          src="https://cdn.test.fanzhi.cn//images/0d/d2/70d5dc70ce6f898142cc288cf52c.jpg?x-oss-process=image/resize,w_288,h_393,m_fill/quality,q_100"
        ></image>
        <view class="item-content">
          <text class="item-title">第{{ item.title }}行</text>
          <text style="color: red; margin-left: 10rpx">虚拟列表展示</text>
          <view class="item-detail">{{ item.detail }}</view>
        </view>
        <view class="item-line"></view>
      </view>
    </qinui-list>
  </div>
</template>

<script lang="ts" setup>
  import { ref } from 'vue';
  import theAjax from '../list/ajax';

  // 虚拟列表节点
  const thePageNode = ref<any>(null);
  // tab start
  const theTabIndex = ref('tab1');
  const theTabList = ref([
    {
      label: '测试1',
      value: 'tab1',
    },
    {
      label: '测试2',
      value: 'tab2',
    },
    {
      label: '测试3',
      value: 'tab3',
    },
    {
      label: '测试4',
      value: 'tab4',
    },
  ]);

  const onTabsChange = () => {
    // 当切换tab或搜索时请调用组件的reload方法,请勿直接调用:queryList方法!!
    thePageNode.value?.reload();
  };
  // tab end

  // 虚拟列表数据 start
  const theDataList = ref<any>([]);

  // 监听虚拟列表数组改变并赋值给virtualList进行重新渲染
  const onVirtualListChange = (vList: any) => {
    theDataList.value = vList;
  };

  const onGetDatas = (thePageNo: number, thePageSize: number) => {
    // 组件加载时会自动触发此方法,因此默认页面加载时会自动触发,无需手动调用
    // 这里的 thePageNo 和 thePageSize 会自动计算好,直接传给服务器即可
    // 模拟请求服务器获取分页数据,请替换成自己的网络请求
    const theParams = {
      pageNo: thePageNo,
      pageSize: thePageSize,
      type: theTabIndex.value,
    };
    theAjax
      .queryListLong(theParams)
      .then((theRes: any) => {
        // 将请求的结果数组传递给 qinui-list
        thePageNode.value.complete(theRes.data.list);
      })
      .catch(() => {
        // 如果请求失败写 thePageNode.value.complete(false);
        // 注意,每次都需要在catch中写这句话很麻烦, qinui-list 提供了方案可以全局统一处理
        // 在底层的网络请求抛出异常时,写 qin.$emit('qinui-list-error-emit'); 即可
        thePageNode.value.complete(false);
      });
  };
  // 虚拟列表数据 end
</script>

<style>
  /* 示例样式 start */
  .banner-view {
    background-color: #007aff;
    color: white;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
  }
  .item {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 20rpx 30rpx;
  }

  .item-content {
    flex: 1;
    margin-left: 20rpx;
  }

  .header {
    background-color: red;
    font-size: 24rpx;
    text-align: center;
    padding: 20rpx 0rpx;
    color: white;
  }

  .item-image {
    height: 150rpx;
    width: 150rpx;
    background-color: #eeeeee;
    border-radius: 10rpx;
  }

  .item-title {
    background-color: red;
    color: white;
    font-size: 26rpx;
    border-radius: 5rpx;
    padding: 5rpx 10rpx;
  }

  .item-detail {
    margin-top: 10rpx;
    border-radius: 10rpx;
    font-size: 28rpx;
    color: #aaaaaa;
    word-break: break-all;
  }

  .item-line {
    position: absolute;
    bottom: 0rpx;
    left: 0rpx;
    height: 1px;
    width: 100%;
    background-color: #eeeeee;
  }
  /* 示例样式 end */
</style>

# API


# Props

参数 说明 类型 默认值 可选值
use-virtual-list 是否使用虚拟列表 Boolean false true | false
force-close-inner-list 强制关闭inner-list,默认为false,如果为true将强制关闭innerList,适用于开启了虚拟列表后需要强制关闭inner-list的情况 Boolean false true | false
idPrefix id 前缀 String zp-id -
fixed 默认配置,z-paging为position: fixed并铺满整个页面,脱离页面文档流。z-paging标签外的view都会被它盖住或盖住它。建议:页面中所有元素写在z-paging标签内(包括自定义的导航栏或者自定义的tabbar),如果需要固定在顶部的则放在slot="top"中,固定在底部的放在slot="bottom",此时z-paging是局部滚动的。
适用场景:一般的页面列表分页 Boolean true -
fixed-cell-height fixed="false" 的时候必须指定每条的高度 String | Number - -
height fixed="false" 的时候必须指定整个列表的高度 String | Number - -
hideEmptyView 是否隐藏空状态展示 Boolean false -

# Events

事件名 说明 回调参数
@scroll 页面滚动的监听事件 滚动数据
@virtualListChange 虚拟列表当前渲染的数组改变时触发,在虚拟列表中只会渲染可见区域内+预加载页面的数据 虚拟列表当前渲染的数组
@query 下拉刷新或滚动到底部时会自动触发此方法。 qiniu-list 加载时也会触发(若要禁止,请设置:auto="false")。pageNo和pageSize会自动计算好,直接传给服务器即可。 参数1:pageNo(当前第几页);参数2:pageSize(每页多少条)(pageSize必须与传给服务器的一致,如果需要修改pageSize,请通过:default-page-size="15"修改)参数3 :from(@query的触发来源:0.用户主动下拉刷新 1.通过reload触发 2.通过refresh触发 3.通过滚动到底部加载更多或点击底部加载更多触发)