Vue + Element UI + Lumen 實現通用表格功能 - 分頁

4Ark發表於2019-02-01

前言

最近在做一個前後端分離的專案,前端使用 Vue+ Element UI,而後端則使用 Lumen 做介面開發,其中分頁是必不可少的一部分,本文就介紹如何基於以上環境做一個簡單、可複用的分頁功能。

先說後端

後端做的事情不多,只需要接受幾個引數,根據引數來獲取資料即可。

需要獲取的引數如下:

  • pageSize(一頁資料的數量)
  • pageIndex(第幾頁的資料)

然後就可以根據這兩個引數計算出偏移量,再從資料庫中取出相應的資料。

假如現在給出的引數為:pageSize=10pageIndex = 2,也就是說每一頁要10條記錄,要第二頁。

計算偏移量的公式為:pageSize * (pageIndex - 1)

基本程式碼如下:

public function getUser(Request $request){
    $pageSize = $request->input('pageSize');
    $pageIndex = $request->input('pageIndex');
    $offset = $pageSize * ($pageIndex - 1);
    return User::offset($offset)
                ->limit($pageSize)
                ->get();
}
複製程式碼

後端基本上只需要做這麼多,就可以完成一個分頁的功能了,但還是有幾處地方需要改進一下:

  • 給引數一個預設值
  • 前端還需要知道整個表的資料的總數
  • 把分頁做成一個公用的函式

改進後的程式碼如下:

private $default_page_size = 30;
private $default_page_index = 1;

// 公用分頁
public function pagination($request, $list) {
	$pageSize = $request->input('pageSize', $this->default_page_size);
	$pageIndex = $request->input('pageIndex', $this->default_page_index);
	$offset = $pageSize * ($pageIndex - 1);
	$total = $list->count();
	$list = $list
            ->offset($offset)
            ->limit($pageSize);
	return [
		'list' => $list->get(),
		'total' => $total,
    ];
}

// 獲取使用者列表
public function getUser(Request $request) {
    $list = User::query();
    /*
    	這裡可以做一些查詢之類的操作
    */
    return $this->pagination($request, $list);
}
複製程式碼

再說前端

前端相對於需要做的事情就比較多了,需要考慮幾點:

  • 獲取資料時需要帶上分頁的引數
  • 分頁引數需要進行本地持久化,以免重新整理頁面回到第一頁(後端設定的預設值)
  • 同樣要抽象出一個通用的分頁元件

獲取資料

這裡我們用 vuex來管理狀態,然後在請求時帶上分頁資料:

store.js:

注意

  • 這裡為了方便展示程式碼,並沒有使用模組化,專案中,最好將使用模組化方便管理。
  • 這裡預設讀者清楚 ES6 的語法
export default new vuex.Store({
    state : {
        user : {
            list: [],
            total: 0,
            pageIndex: 1,
            pageSize: 10,
        }
    },
    mutations: {
		updateUser(state, data) {
			state.user = {
				...state.user,
				...data,
			}
		},  
    },
    actions: {
        async getUser({commit,state,getters}) {
            // $axios 只是我自己封裝的一個函式 這裡並不重要
            const res = await $axios.get('/user',getters.requestData(state.user))
            commit('updateUser',res);
    	},
    },
    getters:{
        requestData(state) {
            return (origin) => {
                const {
                    pageIndex,
                    pageSize,
                } = origin;
                const data = {
                    pageIndex,
                    pageSize,
                };
                return data;
            }
        },
    }
})
複製程式碼

資料持久化

現在如何獲取資料已經搞定了,資料持久化我使用 vuex-localstorage,安裝後,只需要在上面程式碼的基礎上新增:

import createPersist from 'vuex-localstorage'
export default new vuex.Store({
    // 接著上面的
    plugins: [createPersist({
        namespace: 'studio-user',
        initialState: {},
        // ONE_WEEK
        expires: 7 * 24 * 60 * 60 * 1e3
    })]
})
複製程式碼

公用分頁元件

<template>
  <el-Pagination
    background
    layout="total, sizes, prev, pager, next, jumper"
    :total="module.total"
    :current-page.sync="module.pageIndex"
    :page-sizes="module.pageSizes"
    :page-size.sync="module.pageSize"
    @current-change="handleCurrentChange"
    @size-change="handleSizeChange"
  >
  </el-Pagination>
</template>
<script>
export default {
  props: {
    module: Object
  },
  methods: {
    getData() {
      this.$emit("get-data");
    },
    handleCurrentChange() {
      this.getData();
    },
    handleSizeChange(val) {
      this.getData();
    }
  }
};
</script>
複製程式碼

使用分頁元件

<template>
  <div class="container">
	<el-table
        :data="user.list"
        style="width: 100%;"
      >
        <el-table-column
          v-for="(item,index) in columns"
          :key="index"
          :prop="item.prop"
          :label="item.label"
          align="center"
        />
      </el-table>
      <pagination
        :module="user"
        @get-data="getData"
      />
  </div>
</template>
<script>
import Pagination from "@/common/components/Pagination";
import { mapActions, mapState } from "vuex";
export default {
  components: {
    Pagination,
  },
  data: () => ({
    columns: [
      {
        prop: "name",
        label: "姓名"
      },
      {
        prop: "性別",
        label: "sex"
      },
      {
        prop: "年齡",
        label: "age"
      },
    ]
  }),
  created() {
    this.getData();
  },
  methods: {
      ...mapActions({
          getData : "getUser",
      })   
  },
  computed: {
    ...mapState(["user"])
  }
};
</script>
複製程式碼

後記

將一些常用的功能抽象出來,打造一個自己的工具庫,從而使開發效率更高。

最後,貼上剛放假時立的 Flag:寒假待寫文章

最後的最後,安利一下文章開頭說的專案:清技背單詞,上面的程式碼就是從這個專案中copy出來後略作修改的。

感謝觀看,希望我的文章能對您有一些幫助!

相關文章