zoukankan      html  css  js  c++  java
  • 基于Vue的简单通用分页组件

    分页组件是每一个系统里必不可少的一个组件,分页组件分为两部分。第一部分是模版部分,用于显示当前分页组件的状态,例如正在获取数据、没有数据、没有下一页等等;第二部分是分页数据对象,用于封装一个分页组件的属性和方法,例如获取数据的 url、当前第几页(page)、每次加载条数(count)、一共有多少页(totalPage)等等,方法可能会有上一页、下一页、处理数据等等。

    分页数据对象

    import base from '@/api/base'
    
    export default class Pagination {
      constructor({ url, processFunc, processExt, count = 10, isMock = false }) {
        // 数据访问地址
        this.url = url
        // 数据集合
        this.list = []
        // 第几页
        this.page = 1
        // 一共几页
        this.totalPage = 1
        // 加载数据条数
        this.count = count
        // 数据处理函数
        this.processFunc = processFunc
        // 错误处理函数
        this.processExt = processExt
        // 正在加载中
        this.loading = false
        // 参数
        this.params = {}
        // 是否底部
        this.reachBottom = false
        // 是否为空
        this.empty = true
        // 是否需要清除
        this.toClear = false
        // 是否为mock数据
        this.isMock = isMock
      }
    
      /**
       * 加载下一页数据
       */
      async next(args) {
        if (this.loading) {
          // console.warn('page loading!')
          return this
        }
        const param = {
          pageNo: this.page,
          pageSize: this.count
        }
        // 附加参数
        this.loading = true
        try {
          Object.assign(param, args)
          let res
          let data
          try {
            res = await base.get(this.url, param)
            data = res.data
          } catch (e) {
            if (typeof this.processExt === 'function') {
              data = this.processExt(e)
            } else {
              throw new Error(e)
            }
          }
          // 底部判断
          if (data === null || data.length < 1) {
            if (this.toClear) {
              this.clear()
            } else {
              this.reachBottom = true
            }
            return this
          }
          this.empty = false
          // 处理数据
          this._processData(data)
          // 设置数据
          if (this.toClear) {
            this.list = data
            this.toClear = false
          } else {
            this.list = this.list.concat(data)
          }
          ++this.page
          this.totalPage = res.page.totalPages
          if (
            (res.page && res.page.page === res.page.totalPages) ||
            data.length < this.count
          ) {
            this.reachBottom = true
          }
          return this
        } finally {
          this.loading = false
        }
      }
    
      /**
       * 恢复到第一页
       */
      reset() {
        this.empty = true
        this.toClear = true
        this.page = 1
        this.reachBottom = false
      }
    
      clear() {
        this.toClear = false
        this.page = 1
        this.list = []
      }
    
      /**
       * 处理数据(私有)
       */
      _processData(data) {
        if (this.processFunc) {
          for (let i in data) {
            const result = this.processFunc(data[i])
            if (result) {
              data[i] = result
            }
          }
        }
      }
    }
    

    分页模版

    <template>
      <div class="z-page-stat">
        <p v-show="page.loading" class="page-loading">
          <span class="ign-loading"></span>
        </p>
        <div
          class="u-more-btn"
          v-show="showLoadMore && !page.reachBottom && !page.loading && !page.empty"
          @click="$emit('nextPage')"
        >
          <span>查看更多</span>
        </div>
        <p class="reach-btm" v-show="showBtmTx && !page.empty && page.reachBottom">
          到底了~
        </p>
        <div class="page-empty" v-show="!page.loading && page.empty">
          <div class="empty-inner">
            <div class="img-bg" v-if="emptyImg">
              <img
                v-if="!emptyImg || emptyImg == 1"
                src="../../img/empty-page.png"
                alt=""
              />
            </div>
    
            <p class="tx">{{emptyText}}</p>
            <div class="empty-ctn">
              <slot name="empty"></slot>
            </div>
          </div>
        </div>
        <slot name="other"></slot>
      </div>
    </template>
    
    <script>
      export default {
        name: 'pageStatus',
        data() {
          return {}
        },
        props: {
          page: {},
          emptyImg: {},
          emptyText: {
            type: String,
            default: '暂时没有数据'
          },
          showLoadMore: {
            // 是否显示加载更多按钮
            type: Boolean,
            default: false
          },
          showBtmTx: {
            // 到底了文字要不要显示
            type: Boolean,
            default: true
          }
        },
        components: {},
        created: function() {},
        mounted: function() {},
        methods: {}
      }
    </script>
    
    <style lang="stylus" rel="stylesheet/stylus">
      .z-page-stat
        text-align center
        letter-spacing 2px
        color #757575
        line-height 60px
        .page-loading
          .ign-loading
            border-radius 100%
            margin 16px 0
            animation-fill-mode both
            border 2px solid #e8473f /* no */
            border-bottom-color transparent
            height 25px /* no */
            width 25px /* no */
            background transparent !important
            display inline-block
            animation rotate 1s 0s linear infinite
        .page-empty
          position absolute
          left 0
          width 100%
          top 50%
          transform translate(0, -50%)
          .empty-inner
            width 320px
            margin 0 auto
          .img-bg
            position relative
            display inline-block
            width 254px
            height 254px
            background #d6d6d6
            border-radius 50%
            margin-bottom 20px
          img
            width 94px
            margin-top 28px
          .tx
            color #8c8c8c
        .empty-ctn
          .u-btn
            margin-top 90px
            margin-left 20px
            border 2px solid #464646 /* no */
            box-shadow none
            width 168px
            height 62px
            line-height 62px
    </style>
    

    使用组件

    <template>
      <div>
        <div class="card-content" v-for="act in page.list" :key="act.id">
          <p>
            {{act.title}}
          </p>
        </div>
        <p-status :page="page"></p-status>
      </div>
    </template>
    
    <script>
      import { mainList } from '@/api/activity'
      import PageStatus from 'comps/pageStatus.vue'
    
      export default {
        data() {
          return {
            page: mainList()
          }
        },
        mixins: [appPage],
        computed: {},
        created: async function() {
          this.page.next({
            /*传参*/
          })
        },
        components: { 'p-status': PageStatus }
      }
    </script>
    
    // @/api/activity
    import Pagination from '@/utils/Pagination'
    
    /**
     * 列表
     */
    export function mainList() {
      const url = `/activity/activity/list.do`
      return new Pagination({
        url: url
      })
    }
    
  • 相关阅读:
    第二十五节:Java语言基础-面向对象基础
    第二十五节:Java语言基础-面向对象基础
    第二十五节:Java语言基础-面向对象基础
    第二十四节:Java语言基础-讲解数组的综合应用
    第二十四节:Java语言基础-讲解数组的综合应用
    第二十四节:Java语言基础-讲解数组的综合应用
    第二十三节:Java语言基础-详细讲解函数与数组
    第二十三节:Java语言基础-详细讲解函数与数组
    第二十三节:Java语言基础-详细讲解函数与数组
    第二十二节:Java语言基础-详细讲解位运算符与流程控制语句
  • 原文地址:https://www.cnblogs.com/Juliana1992/p/10456442.html
Copyright © 2011-2022 走看看