Vue2.0+ElementUI+PageHelper實現的表格分頁

Vue2.0+ElementUI+PageHelper實現的表格分頁

前言

最近作了一些前端的項目,要對錶格進行一些分頁顯示。表格分頁的方法有不少,從宏觀上來講分爲物理分頁和邏輯分頁,因爲邏輯分頁(即前端分頁)的作法是將數據所有緩存,而後分頁顯示,這樣在數據量較大的時候會對瀏覽器的速度產生影響,因此考慮以後我使用了後端分頁,後端分頁的特色是對當前頁的數據進行請求,每次當頁碼變化或者每頁數據量變化的時候,就從新發一次請求。這裏所用到的技術主要有如下幾種:css

  • Spring
  • SpringMVC
  • Mybatis
  • VueJS 2.0
  • ElementUI

後端數據庫用的是Mysql,其實使用其餘的數據庫也能夠,由於PageHelper插件裏有對於各個數據庫的兼容。PageHelper的本質是插入一個Interceptor,在mybatis的sql語句執行以前進行分頁處理,本質上是加了兩個limit的參數。對於PageHelper的配置和用法,請參考joker_zhou寫的Spring + Mybatis 使用 PageHelper 插件分頁這篇文章,這裏再也不贅述。前端

前端所使用的是最近很火的vuejs框架2.0,這是一個mvvm架構的框架,相似於AngularJS,可是更加輕量。UI框架使用的是由餓了麼團隊推出的elementUI框架,這是一款基於vuejs的框架,正好和咱們的前端框架完美結合,而且封裝了不少組件,開發起來很方便。 
下面就是這個Demo的截圖,實現了基本的增刪改查功能,表格排序是elementUI的表格控件裏自帶的一個屬性,能夠很方便的設置。vue

正文

下面是程序的截圖,右鍵在新標籤頁中打開圖片能夠看得清楚些。 jquery


截圖

 

下面來看一下前端的代碼,首先是引入的文件:git

<link rel="stylesheet" href="/core/element-ui/lib/theme-default/index.css">
    <script src="./js/jquery-3.1.1.min.js"></script>
    <script src="./js/json2.js"></script>
    <script src="./js/vue.min.js"></script>  
    <script src="./js/vue-resource.js"></script>
    <script src="./element-ui/lib/index.js"></script>

 

其中第一行和最後一行是ElementUI的導入包,能夠從ElementUI官網下載到源文件引入,也能夠直接使用CDN的方式來引入:github

<!-- 引入樣式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-default/index.css">
<!-- 引入組件庫 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>

 

倒數第二行vue-resource是vuejs的一個ajax插件,能夠經過XMLHttpRequest或JSONP發起請求並處理響應。簡單的說,就是能夠用來發送ajax請求。ajax

接下來是style樣式sql

<style>
      .el-select .el-input {
        width: 110px;
      }

      .el-table .info-row {
            background: #c9e5f5;
      }   

      #top {
          background:#20A0FF;
          padding:5px;
          overflow:hidden
      }
    </style>

 

HTML body數據庫

 <div id="test">             

        <div id="top">          
            <span style="float:right;"> 
                <el-button type="text" @click="add" style="color:white">添加</el-button>  
                <el-button type="text" @click="deletenames" style="color:white">批量刪除</el-button>        
            </span>                     
        </div>  


        <br/>

        <div style="margin-top:15px">
           <el-input placeholder="請輸入內容" v-model="criteria" style="padding-bottom:10px;">
              <el-select v-model="select" slot="prepend" placeholder="請選擇">
                 <el-option label="id" value="1"></el-option>
                 <el-option label="name" value="2"></el-option>
              </el-select>
              <el-button slot="append" icon="search" v-on:click="search"></el-button>
          </el-input>       

          <el-table
            ref="testTable"       
            :data="tableData"
            style="width:100%"
            border
            :default-sort = "{prop: 'id', order: 'ascending'}"
            @selection-change="handleSelectionChange"   
            @row-click="handleclick"
            :row-class-name = "tableRowClassName"
            >
            <el-table-column
              type="selection"
              >
            </el-table-column>
            <el-table-column
              prop="id"
              label="Id"
              sortable
              show-overflow-tooltip>
            </el-table-column>
            <el-table-column
              prop="name"
              label="姓名"
              sortable>
            </el-table-column>
            <el-table-column label="操做">
              <template scope="scope">
                <el-button
                  size="small"
                  type="primary"
                  @click="handleEdit(scope.$index, scope.row)">編輯</el-button>
                <el-button
                  size="small"
                  type="danger"
                  @click="handleDelete(scope.$index, scope.row)">刪除</el-button>
              </template>
            </el-table-column>
          </el-table>

          <div align="center">
              <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="totalCount">
              </el-pagination>
          </div>
        </div> 
    </div>

    <footer align="center">
        <p>&copy; Vue.js 2.0 + ElementUI分頁Demo</p>
    </footer>

 

接下來是比較重要的建立vue實例。這裏使用ES5的寫法。element-ui

<script>
    var vue = new Vue({         
            el:"#test",
            data: {       
                //表格當前頁數據
                tableData: [],

                //多選數組
                multipleSelection: [],

                //請求的URL
                url:'newstu/querystudentbypage',

                //搜索條件
                criteria: '',

                //下拉菜單選項
                select: '',

                //默認每頁數據量
                pagesize: 10,

                //默認高亮行數據id
                highlightId: -1,

                //當前頁碼
                currentPage: 1,

                //查詢的頁碼
                start: 1,

                //默認數據總數
                totalCount: 1000,
            },

            methods: {

                //從服務器讀取數據
                loadData: function(criteria, pageNum, pageSize){                    
                    this.$http.get(this.url,{parameter:criteria, pageNum:pageNum, pageSize:pageSize}).then(function(res){
                        this.tableData = res.data.pagestudentdata;
                        this.totalCount = res.data.number;
                    },function(){
                        console.log('failed');
                    });                 
                },

                //多選響應
                handleSelectionChange: function(val) {
                    this.multipleSelection = val;
                },

                //點擊行響應
                handleclick: function(row, event, column){
                    this.highlightId = row.id;
                },

                //編輯
                handleEdit: function(index, row) {
                    this.$prompt('請輸入新名稱', '提示', {
                          confirmButtonText: '肯定',
                          cancelButtonText: '取消',
                        }).then(({ value }) => {
                            if(value==''||value==null)
                                return;
                            this.$http.post('newstu/update',{"id":row.id,"name":value},{emulateJSON: true}).then(function(res){
                                this.loadData(this.criteria, this.currentPage, this.pagesize);                              
                            },function(){
                                console.log('failed');
                            });
                        }).catch(() => {

                    });
                },


                //單行刪除
                handleDelete: function(index, row) {
                    var array = [];
                    array.push(row.id);
                    this.$http.post('newstu/delete',{"array":array},{emulateJSON: true}).then(function(res){
                        this.loadData(this.criteria, this.currentPage, this.pagesize);
                    },function(){
                        console.log('failed');
                    });
                },

                //搜索
                search: function(){
                    this.loadData(this.criteria, this.currentPage, this.pagesize);
                },

                //添加
                add: function(){
                        this.$prompt('請輸入名稱', '提示', {
                          confirmButtonText: '肯定',
                          cancelButtonText: '取消',
                        }).then(({ value }) => {
                            if(value==''||value==null)
                                return;
                            this.$http.post('newstu/add',{"name":value},{emulateJSON: true}).then(function(res){
                                this.loadData(this.criteria, this.currentPage, this.pagesize);
                            },function(){
                                console.log('failed');
                            });
                        }).catch(() => {

                    });

                },

                //多項刪除
                deletenames: function(){
                    if(this.multipleSelection.length==0)
                        return;
                    var array = [];
                    this.multipleSelection.forEach((item) => {
                        array.push(item.id);
                    })
                    this.$http.post('newstu/delete',{"array":array},{emulateJSON: true}).then(function(res){
                        this.loadData(this.criteria, this.currentPage, this.pagesize);
                    },function(){
                        console.log('failed');
                    });
                },

                //改變當前點擊的行的class,高亮當前行
                tableRowClassName: function(row, index){
                   if(row.id == this.highlightId)
                   {
                      return 'info-row';
                   }
                },

                //每頁顯示數據量變動
                handleSizeChange: function(val) {
                    this.pagesize = val;
                    this.loadData(this.criteria, this.currentPage, this.pagesize);
                },

                //頁碼變動
                handleCurrentChange: function(val) {
                    this.currentPage = val;
                    this.loadData(this.criteria, this.currentPage, this.pagesize);
                },        

            },      


          });

          //載入數據
          vue.loadData(vue.criteria, vue.currentPage, vue.pagesize);
    </script>  

 

如今對上述代碼進行一個簡單的解釋,tableData是表格當前頁所顯示的數據的數組,當網頁加載出來後,首先執行loadData方法,criteria是當前的搜索條件,默認爲空,第二個參數是當前頁碼,默認爲第一頁,第三個參數爲偏移量,即想查詢的數量,也就是當前每頁所含有的數據量。當頁碼或每頁數據量改變時都會以這些參數的新值做爲參數從新調用這個方法。咱們能夠看一下Controller的代碼:

@ResponseBody
    @RequestMapping(value = "/querystudentbypage", method = RequestMethod.GET)  
    public Map<String, Object> querystudentbypage(@RequestParam(value="parameter")String parameter, 
            @RequestParam(value="pageNum")int pageNum, @RequestParam(value="pageSize")int pageSize) 
    {  
        Page<Student> page = iNewStudentService.selectStudents(parameter, pageNum, pageSize);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("pagestudentdata", page);
        map.put("number", page.getTotal());
        return map;
    } 

 

還有service的實現代碼:

 public Page<Student> selectStudents(String parameter, int pageNum, int pageSize)
    {
        Page<Student> page = PageHelper.startPage(pageNum, pageSize);
        newstudentMapper.selectStudents(parameter);
        return page;
    }

 

mybatis的代碼

<select id="selectStudents" resultMap="NewStudentResultMap">
        select id,name from student where id=#{parameter} or name like CONCAT('%',#{parameter},'%')  
    </select>

 

注:爲了代碼的簡便,這裏對用戶的輸入進行了模糊處理,數據表中的id字段等於用戶的輸入或name字段包含了用戶的輸入均可以被查詢出來。

從上面的service實現類和mabatis的代碼中能夠看出,咱們並無手動去給sql語句加limit,而是在newstudentMapper.selectStudents(parameter);這句代碼以前加入了Page page = PageHelper.startPage(pageNum, pageSize);這句代碼就是對PageHelper的調用,不須要去管PageHelper如何去實現(實際是經過Interceptor),只須要這一句代碼就能夠作出物理分頁。它會對緊跟在它後面的一個sql查詢起做用,而且返回分頁後的當頁代碼。 
Controller中的map咱們能夠看到put了兩個值,一個是返回的List,另外一個是數據總量。前端的表格控件會用到這個LIst,而分頁控件會用到這個數據總量。注意startPage的參數,第一個是想要請求的頁碼,第二個是請求頁的數據量。這兩個要與前端請求時發送的參數相對應。

程序的其餘基本功能包括添加、修改、刪除、批量刪除等,前端的代碼都作了解釋,後端也只是單純的調數據庫而已,這裏就再也不貼上後端的代碼。

注: 
表格行點擊高亮功能在ElementUI的表格控件中經過添加highlight-current-row屬性能夠設置,不太高亮的顏色被封裝到了css文件裏。我這裏沒有用到這個屬性,而是自定義了一個class的style,當點擊某行時把自定義的style賦給當前行。若是對ElementUI自己的高亮顏色不滿意又不想去改css文件的話,能夠像文中這種方式自定義一個行點擊響應。

寫在最後的話

vuejs做爲一個前端控件,在最近幾年愈來愈受歡迎,它的社區很活躍,同時又有大量的開源項目庫與之配套,詳細列表請參考Vue 開源項目庫彙總。若是將vuejs與開源庫整合使用,將大大提高前端開發效率,尤爲是對於像我這樣對前端並非很熟悉的後端工程師,也是能夠對照着官網上面的教程和例子進行前端開發。若是使用ES6的寫法,那麼模塊化會更加輕鬆。

ElementUI也是一套很不錯的組件庫,對於咱們常常用到的表格、表單、時間日期選擇器等經常使用組件都有着很好的封裝和接口。

PageHelper做爲一個國人寫的mybatis分頁插件,有着至關不錯的表現,而且支持當前全部的主流數據庫,使用起來也很方便。

前端開發所須要學習的東西並不比後端開發少多少,並且更須要一個經驗的積累,在此記錄一下學習前端開發的歷程。

項目下載地址: https://github.com/tjfy1992/SpringBoot

相關文章
相關標籤/搜索