這一段時間寫項目用到了Vue+ElementUI,這裏記錄一下使用ElementUI內置分頁插件結合後端SSM框架的實現思路和實現過程。javascript
其中遇到了不少坑,我會盡可能把見到的坑都記錄下來,但願對你有所幫助。html
本案例對應的開源項目地址請看個人GitHub倉庫:前端
首先 讓咱們看一下最終效果:mysql
本博文的主要講一下Vue+ElementUI結合後端SpringMVC實現分頁的實現思路,基本的elementUI用法請自行百度;git
Vue的經常使用語法能夠看個人 博文 。github
關於SSM的整合教程能夠看個人這篇 博文; GitHub。redis
<br/>spring
介紹
本案例中設計到的技術棧:
PageHelper: Mybatis的分頁插件
一、SSM框架的整合教程能夠參考個人這篇博文:手摸手帶你整合SSM框架; GitHub。
二、在後端項目中導入PageHelper.jar
的依賴
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.0.0</version> </dependency>
***注意 使用PageHelper分頁插件除了要導入依賴,還須要在Mybatis配置文件中進行相關配置,並交給Spring進行管理。以下配置便可:
<plugins> <!-- com.github.pagehelper 爲 PageHelper 類所在包名 --> <plugin interceptor="com.github.pagehelper.PageHelper"> <!-- 設置數據庫類型 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL 六種數據庫--> <property name="dialect" value="mysql"/> </plugin> </plugins>
這裏還要注意的是PageHelper5.X版本和PageHelper4.X版本PageHelper類所在的包名是不一樣的。 在Spring配置文件中掃描此配置文件便可:
三、在HTML中導入vue.js
and element-ui
。
好的,至此,咱們把基本的環境已經講過了,下面看下相關前端代碼:
<!-- 列表 --> <el-table ref="user" :data="user" tooltip-effect="dark" style="width: 100%"> <el-table-column prop="id" sortable label="編號" width="80"> </el-table-column> <el-table-column prop="username" sortable label="聯繫人" width="120"> </el-table-column> <el-table-column prop="phone" sortable label="聯繫電話" width="120"> </el-table-column> <el-table-column prop="mailbox" label="電子郵箱" width="150"> </el-table-column> <el-table-column prop="postalCode" sortable label="郵政編碼" width="120"> </el-table-column> <el-table-column prop="date" sortable label="註冊時間" width="200"> </el-table-column> <el-table-column prop="address" label="通信地址" width="200" show-overflow-tooltip> </el-table-column> </el-table> <!-- 分頁 --> <div class="pagination"> <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="pageConf.pageCode" :page-sizes="pageConf.pageOption" :page-size="pageConf.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="pageConf.totalPage"> </el-pagination> </div>
注意咱們上面前端HTML樣式用使用Vue綁定的數據:
一、列表數據
//注意這部分代碼是在Vue實例中的data屬性中定義的 data() { //用戶信息 //element-ui的table須要的參數必須是Array類型的 user: [{ username: '', phone: '', mailbox: '', postalCode: '', date: '', address: '' }], }
上面ElementUI表格中<el-table>
中用Vue綁定的:data="user"
就是這個數據,注意:這裏的user對象中的數據須要是Array類型的,不要問爲何,請去看ElementUI源碼;
二、分頁數據
//注意這部分代碼是在Vue實例中的data屬性中定義的 data() { //定義分頁Config pageConf: { //設置一些初始值(會被覆蓋) pageCode: 1, //當前頁 pageSize: 4, //每頁顯示的記錄數 totalPage: 12, //總記錄數 pageOption: [4, 10, 20], //分頁選項 handleCurrentChange: function () { console.log("頁碼改變了"); } }, } methods: { //pageSize改變時觸發的函數 handleSizeChange(val) {}, //當前頁改變時觸發的函數 handleCurrentChange(val) {}, }
上面<el-pagination>
中綁定的數據就來自這個對象:pageConf
,那麼下面你須要關注<el-pagination>
中的幾個配置參數(方法經過Vue的@
綁定,數據經過Vue的:
綁定):
@size-change
: 表示每頁記錄的個數發生變化時觸發的函數,如:原來是每頁/3條,變爲每頁/6條;handleSizeChange
中包含一個參數表示當前是每頁顯示幾條記錄。
@current-change
: 表示當前頁發生變化時觸發的函數,如:點擊下一頁;handleCurrentChange
中包含一個參數表示當前是第幾頁。
:current-page
: 當前頁,即咱們命名的pageCode
,表示當前頁面上展現的第幾頁。
:page-sizes
: 分頁選項,即頁面提供一個列表讓你選擇每頁顯示多少條記錄,注意這個參數的第一個值表示當前頁是每頁/記錄
,你寫上即生效。
:page-size
: 表示每頁顯示的記錄數,即咱們命名的pageSize
。
:total
: 表示總記錄數,即咱們這個表格中一共要顯示多少條數據。
<br/>
以上代碼可能與截圖中樣式不符,由於我把這篇博文中不涉及的都刪除了。
表格中的數據來自:data
這個綁定的對象數組中,即咱們再Vue實例data中定義的user: [{}]
,前提是你在每個<el-table-column>
中都定義了prop
並標識了user:[{}]
中定義的變量,否則element-ui不知道你想在表格的這一行顯示什麼,固然這已經比咱們經常使用的表格渲染數據方便不少了。
element-ui自帶的分頁插件須要提供數據才能正常顯示分頁信息,這些數據都應該是動態的,因此咱們綁定在pageConf
對象中;由於這些數據應該是後端讀取出來的,即經過獲得後端傳來的分頁數據,咱們才知道這裏的分頁信息應該怎樣定義。
在data中定義的pageConf
是初始化參數,最後會被覆蓋掉,可是要注意pageOption
這個參數,必定要和初始的pageSize
配合服用。
以上涉及兩個函數handleSizeChange
、handleCurrentChange
,咱們要在其觸發時自動改變對應的pageOption
參數。
<br/>
一、<el-table>
中須要渲染的數據僅須要傳入:data="user"
便可,可是這個數據user
必須是一個對象數組,必定是數組
二、想要<el-table>
正確渲染你user
中定義的數據,你必須爲每一個<el-table-column>
定義prop
屬性,綁定對應你想展現的數據,否則ElementUI不知道你想展現什麼。
三、pageOption
分頁選項必定要注意,要配合pageSize
的默認值,不要亂定義,好比:pageSize: 2, pageOption: [10,20,30]
,這樣你就會發現頁碼根本不能正確顯示,由於你設置pageSize:2
表示你想每頁展現2條數據,可是你又定義pageOption: [10,20,30]
第一個參數便是默認被選中的,即你又想每頁顯示10條數據,那麼ElementUI就矇蔽了,不知道你到底想每頁顯示幾條數據。
三、根據上面的參數,以及handleSizeChange
、handleCurrentChange
這兩個函數的參數你就應該想到分頁的實現實際上是pageCode
(當前頁)和pageSize
(每頁顯示的記錄數)和後端進行數據交換的。在前端你須要關心的怎樣把pageSize
和pageCode
傳給後端進行分頁查詢;在後端你須要關心的是怎樣調用pageHelper
插件將分頁的記錄數據(包括totalPage
、user
數據等)return 給前端。
<br/>
定義請求映射路徑:findByPage
@RequestMapping("/findByPage") public PageBean findByPage(@RequestParam("pageCode") int pageCode, @RequestParam("pageSize") int pageSize) { System.out.println("分頁的數據:" + userService.findByPage(pageCode, pageSize)); return userService.findByPage(pageCode, pageSize); }
如上是咱們在Controller中定義的請求映射路徑,其中須要接收兩個參數:pageCode
和pageSize
分別表示當前頁、每頁顯示的記錄數;即前端請求這個方法時只須要將pageCode
和pageSize
傳進來就行,後端使用pageHelper
分頁插件將查詢到的數據進行分頁,並將結果返回給前端。
對於請求映射中包含多個參數的,應該使用@RequestParam()
進行標記,否則可能報錯400等。
<br/>
首先咱們須要定義分頁實體類:PageBean.java
public class PageBean() implements Serialization { //當前頁 private long total; //當前頁記錄 private List rows; }
由於咱們使用了mybatis的分頁插件:PageHelper
,因此PageHelper
最終爲咱們封裝在PageBean
的數據應該是這個樣子的:
**注意:**須要返回JSON格式數據。能夠看到裏面主要包含兩個參數:total
、rows
total
表示當前數據的分頁獲得的總頁數,至關於咱們前端定義的pageCode
。rows
表示當前查詢到數據的集合體。即後端的邏輯比較簡單,由於最麻煩的分頁邏輯,PageHelper
已經幫咱們完成了,咱們須要作的:
一、在Controller中定義請求映射方法:PageBean findByPage(@RequestParam("pageCode")int pageCode, @RequestParam("pageSize")int pageSize){}
二、Controller調用Service,經過PageHelper
分頁插件獲取到這兩個參數pageCode,pageSize,自動進行分頁計算。
三、Service調用Dao,指定對應的SQLSELECT * FROM user
,能夠看到這個SQL僅僅須要查詢全部數據便可,返回的數據類型是com.github.pagehelper.Page
四、Controller須要返回給前端的數據類型是:PageBean
(咱們自定義的),其中有兩個參數:com.github.pagehelper.Page.getTotal()
和com.github.pagehelper.Page.getResult()
。
五、綜上,咱們基本已經獲取到了數據,而後經過SpringMVC提供的註解:@RsponseBody
(局部標識方法)或@RestController
(全局標識類),自動將返回的數據轉換爲JSON格式,而後再發送給前端。
<br/>
前端邏輯相對複雜一些,咱們主要須要關注兩點:
1.進入頁面觸發的事件方法、以及點擊分頁相關的按鈕怎樣和後端交互? 2.如何將後端交互返回的數據賦值給表格中的綁定的數據、以及分頁組件中綁定的數據,並實現HTML頁面的渲染?
進入頁面觸發的事件方法、以及點擊分頁相關的按鈕怎樣和後端交互?
1.有哪些可能被觸發的事件和方法?
created
聲明周期函數中調用findByPage(this.pageConf.pageCode,this.pageConf.pageSize)
(傳入默認的值)。對應的HTML代碼:findByPage(pageCode, pageSize) {},
@size-change
屬性綁定。好比:原來4條/每頁改變爲6條/每頁,就將觸發這個函數;其中的參數val
表示當前頁每頁顯示幾條記錄pageSize = val
。對應的HTML代碼:handleSizeChange(val) { this.findByPage(this.pageConf.pageCode, val); },
每當pageSize改變就須要從新調用findByPage(this.pageConf.pageCode, val)
函數從新計算頁面須要渲染的數據。
@current-change
屬性綁定。好比:點擊下一頁、上一頁,就會觸發這個函數;其中的參數val
表示當前是第幾頁pageCode = val
。對應的HTML代碼:handleCurrentChange(val) { this.findByPage(val, this.pageConf.pageSize); },
每當pageCode改變時就須要從新調用findByPage(val, this.pageConf.pageSize)
函數重新計算頁面須要渲染的數據。
2.分頁相關按鈕是什麼鬼?
在傳統沒有每頁插件的時候,咱們一般會手寫分頁邏輯,那麼就須要爲每個頁面綁定一個觸發方法,而使用了element-ui提供的分頁插件,大大簡化了分頁邏輯,其中點擊的下一頁、上一頁、點擊每頁顯示記錄選項、去第幾頁等這些功能都是ElementUI自動幫咱們綁定了事件。
3.怎樣和後端交互?
和後端實現交互的方法主要是findByPage()
這個核心方法,其相關JS代碼:
findByPage(pageCode, pageSize) { this.$http.post('/user/findByPage.do', {pageCode: pageCode, pageSize: pageSize}).then(result => { this.pageConf.totalPage = result.body.total; this.user = result.body.rows; }); },
如上,findByPage()是咱們定義的分頁的核心方法,全部其餘分頁中觸發的方法都會調用這個方法從新和後端交互,獲取到最新的數據並返回給頁面。其中你須要注意:
findByPage()中包含兩個參數:pageCode、pageSize。
調用vue-resource提供的post請求方法,其中傳入兩個參數pageCode、pageSize;在then()
回調函數中可獲取請求返回的數據。
注意Controller返回的數據就在result
這個參數中,可是實際的數據是在result.body
中的,因此你直接result.total
是獲取不到數據的。
前面已經看到了,後端主要返回兩個封裝了數據的參數:total
(總頁數)、rows
(核心數據)
findByPage方法請求後端獲得了total
和rows
,就應該分別賦值給this.pageConf.totalPage
和this.user
;根據Vue雙向綁定的功能,頁面新的數據會直接渲染出來。
如何將後端交互返回的數據賦值給表格中的綁定的數據、以及分頁組件中綁定的數據,並實現HTML頁面的渲染?
其實第一點中咱們已經講到了,由於Vue有一個雙向綁定的功能,即咱們請求後端將數據賦值給data:{}
中的對象後,HTML頁面會當即渲染新的data
數據。
如何將後端返回的數據賦值給頁面須要展現的數據?
首先是<el-table>
中要渲染的數據,其來自:data="user"
綁定的user對象,咱們須要將後端返回的數據賦值給這個user
根據雙向綁定思想即會更新表格中的數據。
其次就是<el-pagination>
中定義的分頁參數,因爲element-ui分頁插件已經幫咱們完成了不少邏輯計算,咱們須要交互改變的參數只有三個:pageCode
當前頁、pageSize
每頁顯示的記錄數、totalPage
總記錄條數,然後端返回的數據咱們也看過,綜上:咱們只須要將後端返回的總頁數total
賦值給user
對象中的屬性totalPage
便可。
主要JavaScript代碼
findByPage(pageCode, pageSize) { this.$http.post('/user/findByPage.do', {pageCode: pageCode, pageSize: pageSize}).then(result => { this.pageConf.totalPage = result.body.total; this.user = result.body.rows; }); },
<br/>
通過上面的分析,其實不少代碼已經展現出來了,下面咱們看看完整的代碼:
實體類
public class PageBean implements Serializable { //當前頁 private long total; //當前頁記錄 private List rows; ... } public class User implements Serializable { private Long id; //用戶編號 private String username; //用戶名 private String password; //密碼 private String phone; //聯繫電話 private String mailbox; //郵箱 private String address; //地址 private String postalCode; //郵政編碼 private String date; //註冊日期 ... }
Controller
@ResponseBody @RequestMapping("/findByPage") public PageBean findByPage(@RequestParam("pageCode") int pageCode, @RequestParam("pageSize") int pageSize) { return userService.findByPage(pageCode, pageSize); }
Service
import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.instrument.dao.UserDao; import com.instrument.entity.PageBean; import com.instrument.entity.User; ... public PageBean findByPage(int pageCode, int pageSize) { //使用Mybatis分頁插件 PageHelper.startPage(pageCode,pageSize); //調用分頁查詢方法,其實就是查詢全部數據,mybatis自動幫咱們進行分頁計算 Page<User> page = userDao.findByPage(); return new PageBean(page.getTotal(),page.getResult()); }
這裏dao層調用的findByPage()
對應的SQL僅僅是SELECT * FROM 表
。而分頁是調用的startPage()
和Page
函數二者共同完成的分頁邏輯計算,其返回的數據主要是在total
和rows
中封裝着。
mapper.xml
<!-- 分頁查詢 --> <select id="findByPage" resultType="com.instrument.entity.User"> SELECT * FROM user </select>
<div id="#app"> <el-table ref="user" :data="user" tooltip-effect="dark" style="width: 100%"> <el-table-column prop="id" sortable label="編號" width="80"> </el-table-column> <el-table-column prop="username" sortable label="聯繫人" width="120"> </el-table-column> <el-table-column prop="phone" sortable label="聯繫電話" width="120"> </el-table-column> <el-table-column prop="mailbox" label="電子郵箱" width="150"> </el-table-column> <el-table-column prop="postalCode" sortable label="郵政編碼" width="120"> </el-table-column> <el-table-column prop="date" sortable label="註冊時間" width="200"> </el-table-column> <el-table-column prop="address" label="通信地址" width="200" show-overflow-tooltip> </el-table-column> </el-table> <!-- 分頁 --> <div class="pagination"> <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="pageConf.pageCode" :page-sizes="pageConf.pageOption" :page-size="pageConf.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="pageConf.totalPage"> </el-pagination> </div> </div> <script type="text/javascript" src="../vue.js"></script> <script type="text/javascript"> new Vue({ el: '#app' data(){ //用戶信息 //element-ui的table須要的參數必須是Array類型的 user: [{ username: '', phone: '', mailbox: '', postalCode: '', date: '', address: '' }], //定義分頁Config pageConf: { //設置一些初始值(會被覆蓋) pageCode: 1, //當前頁 pageSize: 4, //每頁顯示的記錄數 totalPage: 12, //總記錄數 pageOption: [4, 10, 20], //分頁選項 handleCurrentChange: function () { console.log("頁碼改變了"); } }, }, methods:{ findByPage(pageCode, pageSize) { this.$http.post('/user/findByPage.do', {pageCode: pageCode, pageSize: pageSize}).then(result => { this.pageConf.totalPage = result.body.total; this.user = result.body.rows; }); }, //pageSize改變時觸發的函數 handleSizeChange(val) { this.findByPage(this.pageConf.pageCode, val); }, //當前頁改變時觸發的函數 handleCurrentChange(val) { this.findByPage(val, this.pageConf.pageSize); }, // 獲取全部數據 findAll() { this.$http.post('/user/findAll.do').then(result => { this.user = result.body; }); } }, created(){ this.findAll(); this.findByPage(this.pageConf.pageCode, this.pageConf.pageSize); } }); </script>
以上代碼咱們基本已經解釋過了,惟一沒有提到的就是findAll()
這個方法,要知道,進入到頁面後,首先就是展現全部數據(即便有沒有分頁);那麼就須要在生命週期函數created
中執行findAll()
獲取全部數據直接渲染到頁面上this.user=result.body
便可。其次又由於咱們使用了分頁查詢功能,進入頁面後展現的數據應該是分頁查詢後的數據(由於咱們設置有默認的分頁參數值)。
<br/>
若是你們有興趣,歡迎你們加入個人Java交流技術羣:671017003 ,一塊兒交流學習Java技術。博主目前一直在自學JAVA中,技術有限,若是能夠,會盡力給你們提供一些幫助,或是一些學習方法,固然羣裏的大佬都會積極給新手答疑的。因此,別猶豫,快來加入咱們吧!
<br/>
If you have some questions after you see this article, you can contact me or you can find some info by clicking these links.