vue-element(四) el-table滾動加載

說明

自用

一、自定義指令實現

參考:

vue element-ui table表格滾動加載

    1. template
<template>
  <el-table
    size="mini"
    :height="height"
    highlight-current-row
    v-loading="loading"
    v-loadmore="loadMore"
    :data="tableData"
  >
    <slot></slot>
    <template slot="append">
        <div class="no-more">
          我~是有底線的 (~ ̄▽ ̄)~
        </div>
    </template>
  </el-table>
</template>
    1. script
export default {
  name: 'WbTable',
  // 自定義指令
  //  vue 官方文檔:https://cn.vuejs.org/v2/guide/custom-directive.html
  directives: {
    loadmore: {
      bind (el, binding) {
        const selectWrap = el.querySelector('.el-table__body-wrapper')
        selectWrap.addEventListener('scroll', function () {
          let sign = 100
          const scrollDistance = this.scrollHeight - this.scrollTop - this.clientHeight
          if (scrollDistance <= sign) {
            binding.value()
          }
        })
      }
    }
  },
  props: {
    // 服務端列表數據接口名稱
    url: {
      type: String,
      required: true
    },
    // 服務端列表數據接口請求參數
    params: {
      type: Object,
      required: true
    }
  },
  data () {
    return {
      tableData: [],
      loading: false,
      total: 0
    }
  },
  created () {
    this.limit = this.params.limit ? this.params.limit : 8
    this.offset = this.params.offset ? this.params.offset : 0
    // 根據單元格最小高度計算表格高度
    this.height = this.limit * 45
    this.append(this.params)
  },
  methods: {
    append (params) {
      this.loading = true
      this.$http[this.url]({
        ...params,
        offset: this.offset,
        limit: this.limit
      })
        .then(result => {
          this.tableData = [
            ...this.tableData,
            ...result.data.rows
          ]
          console.log(this.tableData)
          this.total = result.data.total || 0
        })
        .finally(() => {
          this.loading = false
        })
    },
    reload () {
      // 刷新重置 offset 和表格
      this.params.offset = 0
      this.tableData = []

      // api動態加載完 開始重新請求數據
      this.$nextTick(() => {
        this.init(this.params)
      })
    },
    // 滾動事件
    loadMore () {
      const newOffset = this.offset + this.limit
      if (newOffset < this.total && !this.loading) {
        this.offset = newOffset
        this.append(this.params)
      }
    }
  }
}
  • 3.效果


二、與el-infinite-scroll 結合

有大佬已經實現了,查看:

element-ui 的 el-table 上使用無限滾動加載(與自帶的 infinite-scroll 結合):https://blog.csdn.net/baidu_27769027/article/details/101924676
GitHub代碼:https://github.com/yujinpan/el-table-infinite-scroll/blob/master/src/directives/table-infinite-scroll.js

三、 使用vue-infinite-loading實現滾動加載

參考:

官方文檔(中文):https://peachscript.github.io/vue-infinite-loading/zh/
vue elmentui table 滾動加載:http://www.lxweimin.com/p/48df3fd85dd6

1. 安裝

注意:vue-infinite-loading2.0只能在Vue.js2.0中使用。如果你想在Vue.js1.0中使用,請安裝vue-infinite-loading1.3版本

npm install vue-infinite-loading --save
2.引入
import InfiniteLoading from 'vue-infinite-loading'
export default {
  name: 'WbTable',
  components: {InfiniteLoading}
}
3.完整使用
  • template
<template>
  <el-table
    size="mini"
    :height="height"
    highlight-current-row
    v-loading="loading"
    :data="tableData"
  >
    <slot></slot>
    <template slot="append">
      <!--
      @infinite: 滾動事件回調函數,當滾動到距離滾動父元素底部特定距離的時候,會被調用
      distance: 這是滾動的臨界值。default: 100; 如果到滾動父元素的底部距離小于這個值,那么 loadMore 回調函數就會被調用。
      spinner: 通過這個屬性,你可以選擇一個你最喜愛旋轉器作為加載動畫
            'default' | 'bubbles' | 'circles' | 'spiral' | 'waveDots'
      direction: 如果你設置這個屬性為top,那么這個組件將在你滾到頂部的時候,調用on-infinite函數
            'top' | 'bottom'
      forceUseInfiniteWrapper: (boolean | string) 強制指定滾動容器,使用CSS 選擇器
      identifier: 識別號,改變時刷新
      -->
      <infinite-loading
        @infinite="loadMore"
        ref="infiniteLoading"
        :distance="100"
        spinner="bubbles"
        :identifier="infiniteId"
        force-use-infinite-wrapper=".el-table__body-wrapper">
        <!--   orce-use-infinite-wrapper 屬性在存在多個 el-table 需要更詳細的css選擇器   -->
          <div class="no-more" slot="no-more">
            我~是有底線的 (~ ̄▽ ̄)~
          </div>
          <div class="no-more" slot="no-results">
            暫無結果 ???
          </div>
          <div class="no-more" slot="error">
            出錯了 (╯‵□′)╯︵┻━┻
          </div>
      </infinite-loading>
    </template>
  </el-table>
</template>
  • script
import InfiniteLoading from 'vue-infinite-loading'
export default {
  name: 'WbTable',
  components: {InfiniteLoading},
  props: {
    // 服務端列表數據接口名稱
    url: {
      type: String,
      required: true
    },
    // 服務端列表數據接口請求參數
    params: {
      type: Object,
      required: true
    }
  },
  data () {
    return {
      tableData: [],
      loading: false,
      total: 0,
      isOver: false,
      infiniteId: new Date()
    }
  },
  created () {
    this.limit = this.params.limit ? this.params.limit : 8
    this.offset = this.params.offset ? this.params.offset : 0
    // 根據單元格最小高度計算表格高度
    this.height = this.limit * 45
  },
  methods: {
    // 滾動事件
    async loadMore ($state) {
      this.loading = true
      if (!this.isOver) {
        await this.$http[this.url]({
          ...this.params,
          offset: this.offset,
          limit: this.limit
        })
          .then((result) => {
            this.tableData = [
              ...this.tableData,
              ...result.data.rows
            ]
            this.total = result.data.total || 0
            if (this.total <= this.tableData.length) {
              this.isOver = true
              $state.complete() // 全部加載完成
            } else {
              $state.loaded() // 單個數據加載完畢
              this.offset = this.offset + this.limit // 設置下一頁
            }
            console.log(this.tableData, this.total)
          })
          .finally(() => {
            this.loading = false
          })
      }
    },
    reset () {
      this.offset = 0
      this.tableData = []
      this.infiniteId += 1
    }
  }
}

四、手動加載下一頁

運用el-table的插槽append設置一個加載按鈕,手動觸發頁面加載

  • template
<template>
  <el-table
    size="mini"
    highlight-current-row
    :height="tableHeight"
    :data="tableData"
    v-loading="loading"
    empty-text="暫無數據 ???"
  >
    <slot></slot>
    <template slot="append" v-if="total > limit">
      <div v-if="loading" class="table-append loading">
        <i class="fa fa-spinner fa-pulse fa-2x fa-fw"></i>
      </div>
      <div v-else-if="!isOver && !noMore && !isError" class="table-append next" @click="nextPage">
        <i class="fa fa-angle-double-down fa-2x fa-fw arrow"></i>
      </div>
      <div v-else class="table-append ending">
        <span v-show="isError">出錯了 (╯‵□′)╯︵┻━┻</span>
        <span v-show="noMore">暫無數據 ???</span>
        <span v-show="isOver">我~是有底線的 (~ ̄▽ ̄)~</span>
      </div>
    </template>
  </el-table>
</template>
  • script
export default {
  name: 'WbTable',
  props: {
    // 服務端列表數據接口名稱
    url: {
      type: String,
      required: true
    },
    // 服務端列表數據接口請求參數
    params: {
      type: Object,
      required: true
    },
    height: {
      type: [String, Number],
      default () {
        return 0
      }
    }
  },
  data () {
    return {
      tableData: [],
      loading: false,
      total: 0,
      isOver: false,
      isError: false,
      noMore: false
    }
  },
  created () {
    this.limit = this.params.limit ? this.params.limit : 8
    this.offset = this.params.offset ? this.params.offset : 0
    // 取設置的高度,否則按最小高度計算
    this.tableHeight = this.height ? this.height : this.limit * 45 + 80
    this.append(this.params)
  },
  methods: {
    // 列表新增
    async append (params) {
      this.loading = true
      this.$http[this.url]({
        ...params,
        offset: this.offset,
        limit: this.limit
      })
        .then(result => {
          if (!result.data) {
            this.noMore = true
            return
          }
          this.tableData = [
            ...this.tableData,
            ...result.data.rows
          ]
          this.total = result.data.total || 0
          console.log(this.tableData, this.total)
          //  判斷是否需要加載下一頁
          if (this.tableData.length >= this.total) {
            this.isOver = true
          }
        })
        // eslint-disable-next-line handle-callback-err
        .catch(error => {
          this.isError = true
        })
        .finally(() => {
          this.loading = false
        })
    },
    reset () {
      debugger
      this.offset = 0
      this.tableData = []
      this.total = 0
      this.isOver = false
      this.isError = false
      this.noMore = false
      // api動態加載完 開始重新請求數據
      this.$nextTick(() => {
        this.append(this.params)
      })
    },
    nextPage (event) {
      if (!this.isOver) {
        this.offset = this.offset + this.limit
        this.$nextTick(() => {
          this.append(this.params)
        })
      }
    }
  }
}
  • style
<style lang="scss" scoped>
.table-append {
  text-align: center;
  padding: 10px;
}
.ending {
  line-height: 24px;
}
.next {
  /*鼠標 手形狀態*/
  cursor:pointer;
  &:focus,&:hover{
    color:#409EFF;
    border-color:#c6e2ff;
    background-color:#ecf5ff
  }
  &:active{
    color:#3a8ee6;
    border-color:#3a8ee6;
    outline:0
  }
  &::-moz-focus-inner{
    border:0
  }
}
.arrow {
/*  width: 20px;
  height: 20px;
  position: absolute;
  top: 0px;
  right: 50%;
  margin-left: -11px;
  border: 3px solid transparent;
  border-bottom: 3px solid #000;
  border-right: 3px solid #000;
  z-index: 99;
  opacity: .8;*/
  -webkit-transform: rotate(0deg);
  -webkit-animation: arrow 1.5s infinite ease-in-out;
}

@-webkit-keyframes arrow {
  0% {
    opacity:0;
    -webkit-transform:translate(0, -5px) rotate(0deg)
  }
  50% {
    opacity:1;
    -webkit-transform:translate(0, -0px) rotate(0deg)
  }
  100% {
    opacity:0;
    -webkit-transform:translate(0, 5px) rotate(0deg)
  }
}
</style>
<style lang="scss">
  .el-table__body-wrapper::-webkit-scrollbar{
    width: 1px;
  }
  .el-table__body-wrapper::-webkit-scrollbar-thumb{
    border-radius: 1px;
    height: 20px;
    background: rgba(58, 142, 230, 0.51);
  }
  .el-table__body-wrapper::-webkit-scrollbar-track{
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0);
    border-radius: 1px;
    background: rgba(0, 0, 0, 0);
  }
</style>
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 簡說Vue (組件庫) https://github.com/ElemeFE/element" 餓了么出品的VUE...
    Estrus丶閱讀 1,802評論 0 1
  • 基于Vue的一些資料 內容 UI組件 開發框架 實用庫 服務端 輔助工具 應用實例 Demo示例 element★...
    嘗了又嘗閱讀 1,175評論 0 1
  • UI組件 element- 餓了么出品的Vue2的web UI工具套件 Vux- 基于Vue和WeUI的組件庫 m...
    柴東啊閱讀 15,876評論 2 140
  • UI組件 element- 餓了么出品的Vue2的web UI工具套件 Vux- 基于Vue和WeUI的組件庫 m...
    王喂馬_閱讀 6,484評論 1 77
  • UI組件 element- 餓了么出品的Vue2的web UI工具套件 Vux- 基于Vue和WeUI的組件庫 m...
    你猜_3214閱讀 11,160評論 0 118