Vue + Element UI + Lumen 实现通用表格功能 - 分页

2019-02-01 17:23:22 +08:00
 4ark

前言

最近在做一个前后端分离的项目,前端使用 Vue+ Element UI,而后端则使用 Lumen 做接口开发,其中分页是必不可少的一部分,本文就介绍如何基于以上环境做一个简单、可复用的分页功能。

先说后端

后端做的事情不多,只需要接受几个参数,根据参数来获取数据即可。

需要获取的参数如下:

然后就可以根据这两个参数计算出偏移量,再从数据库中取出相应的数据。

假如现在给出的参数为: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出来后略作修改的。

感谢观看,希望我的文章能对您有一些帮助!

2909 次点击
所在节点    Vue.js
4 条回复
crs0910
2019-02-01 19:37:11 +08:00
带查询服务端分页的表格一般参数持久化是做在 url 里吧,方便发给别人的时候还原
current
2019-02-01 21:06:00 +08:00
很莫名的被 @了,个人觉得 v2 实在不是发这种长篇博客的好地方
shellic
2019-02-02 10:08:08 +08:00
@current 笑喷了😂
zuoakang
2019-06-25 15:27:31 +08:00
这类前端边分页与后台太耦合了,pageIndex 和 pageSize 不应该由后台控制,不然你的后台对接其他系统还要考虑兼容。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/532498

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX