【第一个Vue上手小项目Day4】史上最简单的Element-table表格+Pagination 分页(前后端结合)

目录

  • 正文
    • 一、前端设计
      • 1. element-Table 表格
      • 2. element-Pagination 分页
    • 二、结合后端
    • 三、遇见问题及解决
    • 四、总结&源码

前言:
本来搭建好Vue和Springboot前后端框架之后,就不想重复CRUD基础表格的增删改查,觉得ajax是互通的,没有必要再重复重复这些工作。因为,一个小项目要善始善终,不能只有登录就没有后续了。尝试一下Element-ui表格,下拉框,进度条等;Vue引入echarts或其他样式;就不会知道其中的bug和坑,所以,现在开始挖坑…

思路:
参考任意一个后台管理模板的内容:

  • 主界面:大概是以下内容,表格、图表、进度条
    【第一个Vue上手小项目Day4】史上最简单的Element-table表格+Pagination 分页(前后端结合)_第1张图片
  • 分目录:
    • 表格:基础的CRUD、分页,更多有导出表格Excel等。
      【第一个Vue上手小项目Day4】史上最简单的Element-table表格+Pagination 分页(前后端结合)_第2张图片

    更多内容参考:林鑫的demo

本文目标: 在之前vue+Springboot的基础上,实现基础表格,echarts,话不多说,开始挖坑~
提前预告:
用过:Element-table表格+Pagination 分页之后,
? ElementUI是目前博主用过最赞的前端表格处理工具,没有之一 ?

正文

一、前端设计

1. element-Table 表格

参考:element-Table 表格

根据官网api文档,综合了一下表格功能:
左侧全选和反选,日期筛选和排序,标签筛选,关键词搜索,自定义编辑和删除按钮
【第一个Vue上手小项目Day4】史上最简单的Element-table表格+Pagination 分页(前后端结合)_第3张图片
(当然了,这仅是前端界面,根据文档,第一次写,差不多一个小时能全部搞懂,UI框架nice~)
静态页面UserList.vue

<template>
  <div>
    <el-button @click="toggleSelection([tableData[1], tableData[2]])">切换第二、第三行的选中状态el-button>
    <el-button @click="toggleSelection()">取消选择el-button>

    <el-button @click="resetDateFilter">清除日期过滤器el-button>
    <el-button @click="clearFilter">清除所有过滤器el-button>

    <el-table ref="filterTable" :data="tableData.filter(data => !search || data.name.toLowerCase().includes(search.toLowerCase()))" :default-sort="{prop: 'date', order: 'descending'}" border
      tooltip-effect="dark" style="width: 100%" @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55">
      el-table-column>
      <el-table-column prop="date" label="日期" sortable width="180" column-key="date" :filters="[{text: '2016-05-01', value: '2016-05-01'}, {text: '2016-05-02', value: '2016-05-02'}, {text: '2016-05-03', value: '2016-05-03'}, {text: '2016-05-04', value: '2016-05-04'}]"
        :filter-method="filterHandler">
      el-table-column>
      <el-table-column prop="name" label="姓名" width="180">
      el-table-column>
      <el-table-column prop="address" label="地址" :formatter="formatter">
      el-table-column>
      <el-table-column prop="tag" label="标签" width="100" :filters="[{ text: '', value: '' }, { text: '公司', value: '公司' }]"
        :filter-method="filterTag" filter-placement="bottom-end">
        <template slot-scope="scope">
          <el-tag :type="scope.row.tag === '' ? 'primary' : 'success'" disable-transitions>{{scope.row.tag}}el-tag>
        template>
      el-table-column>
       <el-table-column
      align="right">
      <template slot="header" slot-scope="scope">
        <el-input
          v-model="search"
          size="mini"
          placeholder="输入姓名关键字搜索"/>
      template>
      <template slot-scope="scope">
        <el-button
          size="mini"
          @click="handleEdit(scope.$index, scope.row)">Editel-button>
        <el-button
          size="mini"
          type="danger"
          @click="handleDelete(scope.$index, scope.row)">Deleteel-button>
      template>
    el-table-column>
    el-table>
  div>
template>

<script>
  export default {
    data() {
      return {
        tableData: [{
          date: '2016-05-01',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄',
          tag: '家'
        }, {
          date: '2016-05-02',
          name: '李小虎',
          address: '上海市普陀区金沙江路 1517 弄',
          tag: '公司'
        }, {
          date: '2016-05-03',
          name: '张小虎',
          address: '上海市普陀区金沙江路 1519 弄',
          tag: '家'
        }, {
          date: '2016-05-04',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1516 弄',
          tag: '公司'
        }],
        multipleSelection: [],
        search: ''
      }
    },

    methods: {
      //多行全选和反选
      toggleSelection(rows) {
        if (rows) {
          rows.forEach(row => {
            this.$refs.filterTable.toggleRowSelection(row);
          });
        } else {
          this.$refs.filterTable.clearSelection();
        }
      },
      handleSelectionChange(val) {//反选
        this.multipleSelection = val;
      },
      //排序
      formatter(row, column) {
        return row.address;
      },
      //标签查找和清除标签
      resetDateFilter() {
        this.$refs.filterTable.clearFilter('date');
      },
      clearFilter() {
        this.$refs.filterTable.clearFilter();
      },
      filterTag(value, row) {
        return row.tag === value;
      },
      filterHandler(value, row, column) {
        const property = column['property'];
        return row[property] === value;
      },
      //编辑
      handleEdit(index, row) {
        console.log(index, row);
      },
      //删除
      handleDelete(index, row) {
        console.log(index, row);
      }
    }
  }
script>

2. element-Pagination 分页

参考:element-Pagination 分页

在这里插入图片描述

<template>
    <div class="block">
      <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="currentPage"
        :page-sizes="[10, 20, 30, 40]" :page-size="10" layout="total, sizes, prev, pager, next, jumper" :total="40" background>
      el-pagination>
    div>
template>
<script>
  export default {
    methods: {
      handleSizeChange(val) {
        console.log(`每页 ${val} 条`);
      },
      handleCurrentChange(val) {
        console.log(`当前页: ${val}`);
      }
    },
    data() {
      return {
        currentPage: 4
      };
    }
  }
script>

二、结合后端

后端用springboot结合aop封装:【Springboot学习 | 6】Lombok优雅的编码+Aop异常统一管理
返回:code、data、message、success
【第一个Vue上手小项目Day4】史上最简单的Element-table表格+Pagination 分页(前后端结合)_第4张图片
主要Ajax:

    created() {
      this.getUserList();
    },
    methods: {
    getUserList() {
        this.$ajax.get('/user/aop2').then((res) => { //axios发送get请求
          if (res.data) {
            console.log(res.data)
            this.userList = res.data.data;
          } else {
            alert("查询失败")
          }
         })
      }
  }

完整userList.vue

  • 注意data的名称
<template>
  <div>
    <el-button @click="toggleSelection([userList[1], userList[2]])">切换第二、第三行的选中状态el-button>
    <el-button @click="toggleSelection()">取消选择el-button>

    <el-button @click="clearFilter">清除所有过滤器el-button>

    <el-table ref="filterTable" :data="userList.slice((currentPage-1)*pagesize,currentPage*pagesize).filter(data => !search || data.name.toLowerCase().includes(search.toLowerCase()))"
      :default-sort="{prop: 'id', order: 'ascending'}" border tooltip-effect="dark" style="width: 100%" @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55">
      el-table-column>
      <el-table-column prop="id" label="id" sortable width="180">
      el-table-column>
      <el-table-column prop="name" label="姓名" width="180">
      el-table-column>
      <el-table-column prop="age" label="年龄" width="180">
      el-table-column>
      <el-table-column prop="address" label="地址" width="180" :filters="[{ text: '重庆', value: '重庆' }, { text: '北京', value: '北京' },{ text: '上海', value: '上海' }]"
        :filter-method="filterTag" filter-placement="bottom-end">
        <template slot-scope="scope">
          <el-tag :type="scope.row.address === '重庆' ? 'primary' : 'success'" disable-transitions>{{scope.row.address}}el-tag>
        template>
      el-table-column>
      <el-table-column align="right">
        <template slot="header" slot-scope="scope">
          <el-input v-model="search" size="mini" placeholder="输入姓名关键字搜索" />
        template>
        <template slot-scope="scope">
          <el-button size="mini" @click="handleEdit(scope.$index, scope.row)">Editel-button>
          <el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)">Deleteel-button>
        template>
      el-table-column>
    el-table>
    <div class="block">
      <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="currentPage"
        :page-sizes="[10, 20, 30, 40]" :page-size="pagesize" layout="total, sizes, prev, pager, next, jumper" :total="userList.length"
        background>
      el-pagination>
    div>
  div>
template>

<script>
  export default {
    data() {
      return {
        userList: [],
        multipleSelection: [], //全选和反选标记
        search: '', //关键词查找
        currentPage: 1 ,//最初显示默认要跳转的一页
        pagesize:10
      }
    },
    created() {
      this.getUserList();
    },
    methods: {
      //多行全选和反选
      toggleSelection(rows) {
        if (rows) {
          rows.forEach(row => {
            this.$refs.filterTable.toggleRowSelection(row);
          });
        } else {
          this.$refs.filterTable.clearSelection();
        }
      },
      handleSelectionChange(val) { //反选
        this.multipleSelection = val;
      },
      //排序
      formatter(row, column) {
        return row.address;
      },
      //标签查找和清除标签
      resetDateFilter() {
        this.$refs.filterTable.clearFilter('address');
      },
      clearFilter() {
        this.$refs.filterTable.clearFilter();
      },
      filterTag(value, row) {
        return row.address === value;
      },
      filterHandler(value, row, column) {
        const property = column['property'];
        return row[property] === value;
      },
      //编辑
      handleEdit(index, row) {
        console.log(index, row);
      },
      //删除
      handleDelete(index, row) {
        console.log(index, row);
      },
      //分页
      handleSizeChange(size) {
        console.log(`每页 ${size} 条`);
        this.pagesize = size;
      },
      handleCurrentChange(currentPage) {
        console.log(`当前页: ${currentPage}`);
        this.currentPage = currentPage;
      },
      getUserList() {
        this.$ajax.get('/user/aop2').then((res) => { //axios发送get请求
          if (res.data) {
            console.log(res.data)
            this.userList = res.data.data;
          } else {
            this.$message({
              type: 'error',
              message: '查询失败',
              showClose: true
            })
          }
         })
      }
    }
  }
script>

最终效果: 以下全部根据官网教程写出来的,稍稍改动整合:

参考:element-Table 表格

  • 关键词查找(姓名模糊查询)
    通过设置Scoped slot来自定义表头。
    search方法也比较简单,用的分词过滤器类似原理,如果名称是王小虎,则输入即可查询出来:
    el-table :data="tableData.filter(data => !search || data.name.toLowerCase().includes(search.toLowerCase()))"

        data() {
          return {
            userList: [],
            multipleSelection: [], //全选和反选标记
            search: '', //关键词查找
            currentPage: 1 ,//最初显示默认要跳转的一页
            pagesize:10
          }
        }
    

    【第一个Vue上手小项目Day4】史上最简单的Element-table表格+Pagination 分页(前后端结合)_第5张图片

  • 多选,排序

  1. 多选: 实现多选非常简单: 手动添加一个el-table-column,设type属性为selection即可;@selection-change="handleSelectionChange"是控制反选,改变选择状态;

          //多行全选和反选
          toggleSelection(rows) {
            if (rows) {
              rows.forEach(row => {
                this.$refs.filterTable.toggleRowSelection(row);
              });
            } else {
              this.$refs.filterTable.clearSelection();
            }
          },
          handleSelectionChange(val) { //反选
            this.multipleSelection = val;
          },
    
  2. 排序: el-table :default-sort = "{prop: 'date', order: 'descending'}"是降序,ascending是升序。

      //排序
      formatter(row, column) {
        return row.address;
      },
    

    【第一个Vue上手小项目Day4】史上最简单的Element-table表格+Pagination 分页(前后端结合)_第6张图片

  • 分页效果

    除了参考官网:element-Pagination 分页

  1. 分页函数加上变量:

          //分页
          handleSizeChange(size) {
            this.pagesize = size;
          },
          handleCurrentChange(currentPage) {
            this.currentPage = currentPage;
          }
    
  2. 很重要的一步是在el-table标签中:data属性要加上监听:userList.slice((currentPage-1)*pagesize,currentPage*pagesize)
    【第一个Vue上手小项目Day4】史上最简单的Element-table表格+Pagination 分页(前后端结合)_第7张图片

  • 标签筛选
        data() {
          return {
            userList: [],
            multipleSelection: [], //全选和反选标记
            search: '', //关键词查找
            currentPage: 1 ,//最初显示默认要跳转的一页
            pagesize:10
          }
        }
     。。。。。。。。。。
      //标签查找和清除标签
      resetDateFilter() {
        this.$refs.filterTable.clearFilter('address');//注意对应的标签
      },
      clearFilter() {
        this.$refs.filterTable.clearFilter();
      },
      filterTag(value, row) {
        return row.address === value;
      },
      filterHandler(value, row, column) {
        const property = column['property'];
        return row[property] === value;
      },
    
    【第一个Vue上手小项目Day4】史上最简单的Element-table表格+Pagination 分页(前后端结合)_第8张图片

三、遇见问题及解决

  1. 问题:error:The template root requires exactly one element.
    原因:因为vue的模版中只有能一个根节点,所以在< template>中插入第二个元素就会报错
    解决:将中的元素先用一个< div>包起来。

    <template>
      <div>
        <el-button>XXXel-button>
        <el-table>el-table>
      div>
    template>
    
  2. 中文乱码,解决方法:后端配置application.properties加上&characterEncoding=UTF8
    【第一个Vue上手小项目Day4】史上最简单的Element-table表格+Pagination 分页(前后端结合)_第9张图片

四、总结&源码

总结:
element-UI框架分页,查询,排序都是全查询get全部信息之后,再对数据进行分页,排序等:

首先,element-table比之前自己用各原生page-taglib ?、PageHelper分页 ?、LayUI ? 分页方法都要nb‘,大赞Pagination 分页 ?

其次,分词 查询、排序、筛选 思想,比之前我自己肝了三天的条件查询,然后再后端控制注入 要科学。

本次学习颇有收获。

源码:

  • 前端: Vue-Day4
  • 后端:Springboot-Day7
  • sql:t_user

你可能感兴趣的:(#,Vue,Java前后端开发学习)