当前位置: 首页 > 工具软件 > mescroll > 使用案例 >

mescroll.js 的下拉刷新和上拉加载 tab切换

郜联
2023-12-01

1. 执行npm命令安装mescroll : npm install --save mescroll.js

2. 引入mescroll组件 : import MescrollVue from 'mescroll.js/mescroll.vue’

<!-- 1.修改请求路径 参数
     2.可以在created里面请求看一下是否成功  然后在将上拉下拉刷新请求修改  在查看属性渲染数据
     3.npm install less less-loader --save
    -->
<template>
  <div>
    <nav-bar />
    <demo-section>
    //全引入Vant-Ul组件  才能使用van-tabs
      <van-tabs v-model="tabType" type="card" @click="tabChange">
        <van-tab :title="`${tab.pending.name}(${tab.pending.dataNum})`" name="0"></van-tab>
        <van-tab :title="tab.deal.name" name="1"></van-tab>
        <van-tab :title="tab.done.name" name="2"></van-tab>
        <!-- 待处理 -->
        <mescroll-vue
          v-show="tabType == 0"
          ref="mescroll0"
          :down="getMescrollDown(0)"
          :up="getMescrollUp(0)"
          @init="mescrollInit0"
        >
          <ul class="itemlist" id="itemlist0">
            <li class="card" v-for="item in pending.data" :key="item.oafdUuid">
              <router-link :to="{name: getType(item, 'name'), query: getType(item, 'query', 0)}">
                <div class="card-body">
                  <span class="tag tag-blue">{{ getType(item, 'text') }}</span
                  >{{ item.oafdSubjectos }}
                </div>
                <div class="card-footer">
                  <span>{{ item.oafdCusrname }}</span
                  ><i class="time">{{ item.oafdCdate | formatDate('yyyy-MM-dd hh:mm') }}</i>
                </div>
              </router-link>
            </li>
          </ul>
        </mescroll-vue>
        <!-- 已处理 -->
        <mescroll-vue
          v-show="tabType == 1"
          ref="mescroll1"
          :down="getMescrollDown(1)"
          :up="getMescrollUp(1)"
          @init="mescrollInit1"
        >
          <ul class="itemlist" id="itemlist1">
            <li class="card" v-for="item in deal.data" :key="item.oafdUuid">
              <router-link :to="{name: getType(item, 'name'), query: getType(item, 'query', 1)}">
                <div class="card-body">
                  <span class="tag tag-gray">{{ getType(item, 'text') }}</span
                  >{{ item.oafdSubjectos }}
                </div>
                <div class="card-footer">
                  <span>{{ item.oafdCusrname }}</span
                  ><i class="time">{{ item.oafdCdate | formatDate('yyyy-MM-dd hh:mm') }}</i>
                </div>
              </router-link>
            </li>
          </ul>
        </mescroll-vue>
        <!-- 已完成 -->
        <mescroll-vue
          v-show="tabType == 2"
          ref="mescroll1"
          :down="getMescrollDown(2)"
          :up="getMescrollUp(2)"
          @init="mescrollInit2"
        >
          <ul class="itemlist" id="itemlist2">
            <li class="card" v-for="item in done.data" :key="item.oafdUuid">
              <router-link :to="{name: getType(item, 'name'), query: getType(item, 'query', 2)}">
                <div class="card-body">
                  <span class="tag tag-gray">{{ getType(item, 'text') }}</span
                  >{{ item.oafdSubjectos }}
                </div>
                <div class="card-footer">
                  <span>{{ item.oafdCusrname }}</span
                  ><i class="time">{{ item.oafdCdate | formatDate('yyyy-MM-dd hh:mm') }}</i>
                </div>
              </router-link>
            </li>
          </ul>
        </mescroll-vue>
      </van-tabs>
    </demo-section>
  </div>
</template>
<script>
  // 引入mescroll的vue组件
import MescrollVue from 'mescroll.js/mescroll.vue'
import {getFiledispatchList} from '@/api/official-review.js'
export default {
  components: {
    MescrollVue,
  },
  data() {
    return {
      pending: {
        mescroll: null,
        isListInit: false,
        data: []  //请求的列表数据
      },
      deal: {
        mescroll: null,
        isListInit: false,
        data: []
      },
      done: {
        mescroll: null,
        isListInit: false,
        data: []
      },
      //tab切换的参数 pending deal done
      tab: {
        pending: {
          name: '待处理',
          dataNum: 0
        },
        deal: {
          name: '已处理'
        },
        done: {
          name: '已完成'
        }
      },
      //控制tab切换的变量
      tabType: 0
    }
  },
  beforeRouteEnter(to, from, next) {
    next(vm => {
      setTimeout(() => {
        // 如果是从表单详情或新建表单返回 则回写当前类型
        let theType
        //official-send-view  路径时你要跳转的详情也路径
        if (from.name == 'official-send-view') {
          theType = localStorage.getItem('listTabType')
          //这串代码的意思时在vm.tab.pending上添加dataNum属性名 只是localStorage.getItem('dataNum')
          vm.$set(vm.tab.pending, 'dataNum', localStorage.getItem('dataNum'))
        } else {
          theType = 0
        }
        vm.tabType = theType
        vm.tabChange(theType)
      })
    })
  },
  beforeRouteLeave(to, from, next) {
    // 如果是进入表单详情或新建表单 则保存当前的类型 否则清空
    if (to.name == 'official-send-view') {
      localStorage.setItem('listTabType', this.tabType)
      localStorage.setItem('dataNum', this.tab.pending.dataNum)
    } else {
      localStorage.removeItem('listTabType')
      localStorage.removeItem('dataNum')
    }
    next()
  },
  methods: {
    // mescroll组件初始化的回调,可获取到mescroll对象
    //tab切换时的回调函数
    mescrollInit0(mescroll) {
      mescroll.tabType = 0
      this.pending.mescroll = mescroll
    },
    mescrollInit1(mescroll) {
      mescroll.tabType = 1
      this.deal.mescroll = mescroll
    },
    mescrollInit2(mescroll) {
      mescroll.tabType = 2
      this.done.mescroll = mescroll
    },
    // 多mescroll的配置,需通过方法获取,保证每个配置是单例
    getMescrollDown(tabNum) {
        //id="itemlist1"
      let wrapId = 'itemlist' + tabNum //拼接和的id
      return {
        auto: false,
        callback: this.downCallback,
        empty: {
          warpId: wrapId,
          tip: '— 暂无更多数据 —'
        }
      }
    },
    getMescrollUp(tabNum) {
      let wrapId = 'itemlist' + tabNum
      return {
        auto: false,
        callback: this.upCallback, // 上拉回调,此处可简写; 相当于 callback: function (page) { upCallback(page); }
        htmlNodata: '<p class="upwarp-nodata">— 暂无更多数据 —</p>',
        noMoreSize: 1, // 如果列表已无数据,可设置列表的总数量要大于半页才显示无更多数据;避免列表数据过少(比如只有一条数据),显示无更多数据会不好看; 默认5
        page: {
          //当前第几页
          num: 0,
          //当前页数的数量
          size: 10
        },
        empty: {
          warpId: wrapId,
          tip: '— 暂无更多数据 —'
        }
      }
    },
    //上拉加载的回调
    downCallback(mescroll) {
      // 这里加载你想下拉刷新的数据, 比如刷新sent的轮播数据
      if (mescroll.tabType == 0) {
        // loadSwiper();
      } else if (mescroll.tabType == 1) {
        // ....
      } else if (mescroll.tabType == 2) {
        // ....
      }
      mescroll.resetUpScroll() // 触发下拉刷新的回调,加载第一页的数据
    },
    /* 上拉加载的回调 page = {num:1, size:10}; num:当前页 从1开始, size:每页数据条数 */
    upCallback(page, mescroll) {
      mescroll.endByPage(page.num * page.size, page.num)
      let currentTab
      if (mescroll.tabType == 0) {
        currentTab = this.pending
        currentTab.isListInit = true // 标记列表已初始化,保证列表只初始化一次
        getFiledispatchList({
         //动态的页数
          'page.start': String(page.num == 1 ? 0 : currentTab.data.length),
          'page.limit': '10',
          'strMap.type': 'pending',
          'strMap.searchKeyWords': '',
          'strMap.postType': 'dd'
        })
          .then(response => {
            if (response.success && response.data.length == 0) {
              if (page.num == 1) {
                currentTab.data = []
                this.$set(this.tab.pending, 'dataNum', 0)
              }
            }
            if (response.success && response.data.length > 0) {
              const arr = response.data
              if (page.num == 1) {
                currentTab.data = []
              }
              currentTab.data = currentTab.data.concat(arr)
              this.$set(this.tab.pending, 'dataNum', response.recordcount)

              this.$nextTick(() => {
                mescroll.endSuccess(response.recordcount)
              })
            } else {
              mescroll.endDownScroll()
              mescroll.endUpScroll(true)
            }
          })
          .catch(e => {
            console.log(e)
            mescroll.endErr()
          })
      } else if (mescroll.tabType == 1) {
        currentTab = this.deal
        currentTab.isListInit = true // 标记列表已初始化,保证列表只初始化一次
        getFiledispatchList({
          //动态的页数
          'page.start': String(page.num == 1 ? 0 : currentTab.data.length),
          'page.limit': '10',
          'strMap.type': 'deal',
          'strMap.searchKeyWords': '',
          'strMap.postType': 'dd'
        })
          .then(response => {
            if (response.success && response.data.length == 0) {
              if (page.num == 1) {
                currentTab.data = []
              }
            }
            if (response.success && response.data.length > 0) {
              const arr = response.data
              if (page.num == 1) {
                currentTab.data = []
              }
              currentTab.data = currentTab.data.concat(arr)

              this.$nextTick(() => {
                mescroll.endSuccess(response.recordcount)
              })
            } else {
              mescroll.endDownScroll()
              mescroll.endUpScroll(true)
            }
          })
          .catch(e => {
            console.log(e)
            mescroll.endErr()
          })
      } else if (mescroll.tabType == 2) {
        currentTab = this.done
        currentTab.isListInit = true // 标记列表已初始化,保证列表只初始化一次
        getFiledispatchList({
          'page.start': String(page.num == 1 ? 0 : currentTab.data.length),
          'page.limit': '10',
          'strMap.type': 'done',
          'strMap.searchKeyWords': '',
          'strMap.postType': 'dd'
        })
          .then(response => {
            if (response.success && response.data.length == 0) {
              if (page.num == 1) {
                currentTab.data = []
              }
            }
            if (response.success && response.data.length > 0) {
              const arr = response.data
              if (page.num == 1) {
                currentTab.data = []
              }
              currentTab.data = currentTab.data.concat(arr)

              this.$nextTick(() => {
                mescroll.endSuccess(response.recordcount)
              })
            } else {
              mescroll.endDownScroll()
              mescroll.endUpScroll(true)
            }
          })
          .catch(e => {
            console.log(e)
            mescroll.endErr()
          })
      }
    },
    // 切换菜单
    tabChange(name) {
      let newTab = this.getTabData(name) // 新转换的列表
      if (!newTab.isListInit) {
        newTab.mescroll.triggerDownScroll() // 加载列表
      }
    },
    // 获取菜单对应的数据
    getTabData(tabNum) {
      if (tabNum == null) tabNum = this.tabNum
      if (tabNum == 0) {
        return this.pending
      } else if (tabNum == 1) {
        return this.deal
      } else {
        return this.done
      }
    },
    // 获取每条数据对应的参数
    getType(data, prop, tabType) {
      const typeObj = {
        text: '发文管理',
        name: 'official-send-view',  //跳转详情也路径
        //穿过去的参数
        query: {
          uuid: data.oafdUuid,
          //详情页数据不同时进行的判断
          hideBtn: tabType != '0' ? 'yes' : 'no',
          openType: 1
        }
      }
      return typeObj[prop]
    }
  }
}
</script>
<style lang="less" scoped>
// tab 切换
@import '../../../style/common/tabs.less';
.mescroll {
  position: fixed;
  top: 102px;
  bottom: 0;
  height: auto;
}
.mescroll-padding {
  bottom: 48px;
}
/deep/ .mescroll-upwarp {
  min-height: 20px;
  line-height: 20px;
  padding: 8px 0;
  font-size: 16px;
}
/deep/ .mescroll-upwarp .upwarp-nodata {
  font-size: 16px;
  color: rgba(25, 31, 37, 0.56);
}
/deep/ .mescroll-empty {
  min-height: 20px;
  line-height: 20px;
  padding: 8px 0;
  .empty-tip {
    margin-top: 0;
    font-size: 12px;
    color: rgba(25, 31, 37, 0.56);
  }
}
// 列表
.itemlist {
  padding: 16px;
  .card {
    padding: 20px 16px;
    background: rgba(255, 255, 255, 1) url('../../../assets/meeting/icon2.png') 92% bottom no-repeat;
    background-size: 52px;
    box-shadow: 0px 2px 4px 0px rgba(25, 31, 37, 0.04);
    border-radius: 6px;
    .tag {
      margin-right: 5px;
      padding-left: 6px;
      padding-right: 16px;
      display: inline-block;
      min-width: 68px;
      height: 26px;
      line-height: 26px;
      font-size: 14px;
      color: #fff;
      box-sizing: border-box;
      vertical-align: middle;
      &.tag-blue {
        background: url('../../../assets/official-review/tag-blue.png');
        background-size: 100% 100%;
      }
      &.tag-gray {
        background: url('../../../assets/official-review/tag-gray.png');
        background-size: 100% 100%;
      }
    }
    .card-body {
      margin-bottom: 14px;
      line-height: 28px;
      font-size: 20px;
      color: rgba(25, 31, 37, 1);
    }
    .card-footer {
      display: flex;
      align-items: center;
      line-height: 20px;
      font-size: 16px;
      color: rgba(25, 31, 37, 0.56);
      span {
        margin-right: 10px;
        vertical-align: middle;
      }
      i {
        font-style: normal;
        vertical-align: middle;
      }
      .doc {
        display: inline-block;
        margin-right: 4px;
      }
    }
  }
  .card + .card {
    margin-top: 16px;
  }
}
// 筛选
.filter-panel {
  padding-top: 44px;
  .filter-title {
    padding: 12px 16px 7px;
    line-height: 21px;
    font-size: 15px;
    color: rgba(25, 31, 37, 1);
    box-sizing: content-box;
  }
  .filter-body {
    ul {
      padding: 0 12px 18px;
      display: flex;
      flex-wrap: wrap;
    }
    li {
      padding: 5px 4px;
      flex-basis: 33.33%;
      box-sizing: border-box;
    }
    p {
      display: flex;
      justify-content: center;
      align-items: center;
      height: 34px;
      font-size: 14px;
      background: rgba(25, 31, 37, 0.04);
      color: rgba(25, 31, 37, 0.72);
      border: 1px solid rgba(151, 151, 151, 0.04);
      border-radius: 3px;
      text-align: center;
      &.active {
        color: rgba(50, 150, 250, 1);
        border: 1px solid rgba(50, 150, 250, 1);
        background: rgba(50, 150, 250, 0.04);
      }
    }
  }
  .filter-footer {
    display: flex;
    button {
      margin: 0;
      padding: 0;
      display: flex;
      flex-basis: 50%;
      height: 44px;
      font-size: 17px;
      justify-content: center;
      align-items: center;
      border: none;
      outline: none;
    }
    .btn-reset {
      color: rgba(50, 150, 250, 1);
      background: rgba(50, 150, 250, 0.08);
    }
    .btn-confirm {
      color: rgba(255, 255, 255, 1);
      background: rgba(50, 150, 250, 1);
    }
  }
}
</style>

 类似资料: