V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
4ark
V2EX  ›  Vue.js

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

  •  
  •   4ark ·
    gd4ark · 2019-02-01 17:23:22 +08:00 · 2894 次点击
    这是一个创建于 2128 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前言

    最近在做一个前后端分离的项目,前端使用 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出来后略作修改的。

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

    4 条回复    2019-06-25 15:27:31 +08:00
    crs0910
        1
    crs0910  
       2019-02-01 19:37:11 +08:00 via iPhone
    带查询服务端分页的表格一般参数持久化是做在 url 里吧,方便发给别人的时候还原
    current
        2
    current  
       2019-02-01 21:06:00 +08:00
    很莫名的被 @了,个人觉得 v2 实在不是发这种长篇博客的好地方
    shellic
        3
    shellic  
       2019-02-02 10:08:08 +08:00 via Android
    @current 笑喷了😂
    zuoakang
        4
    zuoakang  
       2019-06-25 15:27:31 +08:00
    这类前端边分页与后台太耦合了,pageIndex 和 pageSize 不应该由后台控制,不然你的后台对接其他系统还要考虑兼容。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5394 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 09:32 · PVG 17:32 · LAX 01:32 · JFK 04:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.