自定義元件開發:使用v-model封裝el-pagination元件

阿拉伯1999發表於2021-07-07

1、前言

  通過封裝el-pagination元件開發自定義分頁元件的類似文章網上已經有很多了,但看了一圈,總是不如意,於是決定還是自己動手搞一個。

2、背景

2.1、常規分頁處理方法

  利用el-pagination元件的常規做法如下:

  模板部分:

        <el-pagination @size-change="handleSizeChange"
            @current-change="handleCurrentChange" :current-page="pageInfo.pagenum"
            :page-sizes="[5, 10, 15, 20]" :page-size="pageInfo.pagesize"
            layout="total, sizes, prev, pager, next, jumper" :total="pageInfo.total"
            background>
        </el-pagination>

  指令碼部分:

export default {
  data() {
    return {
      formData : {
        //查詢資訊
        queryInfo:{
          userType  : 0,
          deleteFlag: 2,  //表示所有型別
          pagenum   : 1,
          pagesize  : 10      
        },

        // 使用者型別選擇框當前選中顯示標籤值
        userTypeLabel : "所有型別",

        // 使用者狀態選擇框當前選中顯示標籤值
        userStatusLabel : "所有型別"
      },
        
      // 分頁資訊
      pageInfo:{
        pagenum   : 1,
        pagesize  : 10,
        total     : 0
      }
    }
  },
  methods: {
    // 查詢使用者資訊列表
    queryUsers(){
      let _this = this;
      //console.log(this.pageInfo);

      this.formData.queryInfo.pagenum = this.pageInfo.pagenum;
      this.formData.queryInfo.pagesize = this.pageInfo.pagesize;

      this.instance.queryUsers(
        this.$baseUrl,this.formData.queryInfo
      ).then(res => {
        //console.log(res.data);
        if (res.data.code == this.global.SucessRequstCode){
          //如果查詢成功
          _this.pageInfo.total = res.data.data.length;
          _this.userInfoList = res.data.data;
        }else{
          alert(res.data.message);
        }
      }).catch(error => {
        alert('查詢失敗!');            
        console.log(error);
      });
    },    
    // 每頁條數改變
    handleSizeChange(newSize) {
        this.pageInfo.pagesize = newSize;
        this.queryUsers();
    },
    // 當前頁碼改變
    handleCurrentChange(newPage) {
        this.pageInfo.pagenum = newPage;
        this.queryUsers();
    }
  }

2.2、問題分析

  每個分頁查詢,都需要這麼來一套,有點簡單重複,又略有不同,即查詢資料的方法會不同。

  對於有強迫症的程式猿來說,簡單重複的程式碼無疑非常令人不爽。因此,需要將之元件化。

  分析el-pagination分頁元件:

  1. 有三個核心屬性引數,分別是:當前頁碼(current-page)、每頁條數(page-size)、總記錄條數(total)。核心屬性引數通過繫結父元件頁面資料,實行雙向聯動。其中當前頁碼和每頁條數一般通過操作分頁子元件來改變,總記錄條數通過查詢資料後由父元件進行設定。
  2. 有兩個事件:分別是:@size-change(每頁條數改變事件)、@current-change(當前頁碼改變事件)。這兩個事件,分別繫結父元件的對應事件處理方法handleSizeChange和handleCurrentChange,兩者均呼叫查詢資料的方法,查詢資料的方法中,得到結果集後,設定總記錄條數。

  自定義分頁元件的開發目標:消除父元件的handleSizeChange和handleCurrentChange的繫結事件方法。

  思路:使用v-model繫結分頁資訊物件,分頁資訊物件包括3個核心屬性引數,即上述的pageInfo。然後分頁事件直接繫結查詢資料的方法。

3、方案實施

3.1、自定義分頁元件

  編寫一個自定義分頁元件程式碼,檔案為/src/Pagination.vue。程式碼如下:

<template lang="html">
  <div class="pagination">
    <el-pagination 
      @size-change="handleSizeChange" 
      @current-change="handleCurrentChange"
      :current-page.sync="pageInfo.pagenum"  
      :page-size="pageInfo.pagesize" 
      :page-sizes="pageSizes"
      :total="pageInfo.total"
      layout="total, sizes, prev, pager, next, jumper"
      background >
    </el-pagination>
  </div>   
</template>

<script>
  export default {
    name  : "pagination",
    model : {
        prop    : 'pageInfo',
        event   : 'change'
    },
    props : {
      // 每頁條數選擇項
      pageSizes: {
        type: Array,
        default() {
          return [5, 10, 15, 20];
        }
      },
      // v-model繫結的資料物件
      pageInfo: {
        type: Object,
        reuqired:true
      }
    },
    data(){
      return {            
      }
    },
    methods: {
      handleSizeChange(newSize) {
        var newValue={
					pagesize : newSize,
					pagenum : newSize <= this.total  ?  1  :  this.pageInfo['pagenum'] 
				};
        this.$emit('change',Object.assign(this.pageInfo,newValue));
        this.$emit('pagination');
      },
      handleCurrentChange(newPage) {
        this.$emit('change',Object.assign(this.pageInfo,{pagenum : newPage}));
        this.$emit('pagination');
      }
    }    
  }
</script>

<style lang="css" scoped>
.pagination {
    padding: 10px 0;
    text-align: center;
}
</style>

  自定義分頁元件,名稱為pagination,其使用v-model,實現雙向資料通訊。當頁碼或每頁條數改變時,觸發分頁事件@pagination,提供與父元件方法繫結。

  此處約定了pageInfo的欄位結構如下:

      pageInfo:{
        pagenum   : 1,	//Number
        pagesize  : 10,	//Number
        total     : 0	//Number
      }

  父元件必須提供相同結構的資料物件來繫結元件內部的pageInfo物件。

3.2、註冊分頁元件

  然後註冊此分頁元件,在main.js中加入下列程式碼:

import pagination  from '@/components/Pagination.vue'

// 註冊分頁外掛
Vue.component('pagination', pagination)

3.3、父元件呼叫方法

  用pagination元件修改前面第二章的程式碼。

  模板部分:

        <!-- 分頁區域 -->
        <pagination v-model="pageInfo" @pagination="queryUsers"></pagination>

  指令碼部分:

export default { 
  data() {
    return {
      formData : {
        //查詢資訊
        queryInfo:{
          userType  : 0,
          deleteFlag: 2,  //表示所有型別
          pagenum   : 1,
          pagesize  : 10      
        },

        // 使用者型別選擇框當前選中顯示標籤值
        userTypeLabel : "所有型別",

        // 使用者狀態選擇框當前選中顯示標籤值
        userStatusLabel : "所有型別"
      },
        
      // 分頁資訊
      pageInfo:{
        pagenum   : 1,
        pagesize  : 10,
        total     : 0
      }
    }
  },
  methods: {
    // 查詢使用者資訊列表
    queryUsers(){
      let _this = this;
      //console.log(this.pageInfo);

      this.formData.queryInfo.pagenum = this.pageInfo.pagenum;
      this.formData.queryInfo.pagesize = this.pageInfo.pagesize;

      this.instance.queryUsers(
        this.$baseUrl,this.formData.queryInfo
      ).then(res => {
        //console.log(res.data);
        if (res.data.code == this.global.SucessRequstCode){
          //如果查詢成功
          _this.pageInfo.total = res.data.data.length;
          _this.userInfoList = res.data.data;
        }else{
          alert(res.data.message);
        }
      }).catch(error => {
        alert('查詢失敗!');            
        console.log(error);
      });
    }
  }

  這樣,就去掉了handleSizeChange和handleCurrentChange事件響應方法了。分頁資訊發生改變時,觸發繫結的queryUsers方法。

  另外,如需調整pageSizes,則在模板處類似如下設定:

:pageSizes=[10,20,30,50,100]

4、參考文章

  此元件開發主要參考了下列文章:

相關文章