Vue+ElementUI+SpringMVC實現分頁

Vue + ElementUI + SpringMVC實現分頁

這一段時間寫項目用到了Vue+ElementUI,這裏記錄一下使用ElementUI內置分頁插件結合後端SSM框架的實現思路和實現過程。javascript

其中遇到了不少坑,我會盡可能把見到的坑都記錄下來,但願對你有所幫助。html

本案例對應的開源項目地址請看個人GitHub倉庫:前端

首先 讓咱們看一下最終效果:mysql

起步

本博文的主要講一下Vue+ElementUI結合後端SpringMVC實現分頁的實現思路,基本的elementUI用法請自行百度;git

Vue的經常使用語法能夠看個人 博文github

關於SSM的整合教程能夠看個人這篇 博文GitHubredis

<br/>spring

介紹

本案例中設計到的技術棧:

準備

一、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配合服用。

  • 以上涉及兩個函數handleSizeChangehandleCurrentChange,咱們要在其觸發時自動改變對應的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就矇蔽了,不知道你到底想每頁顯示幾條數據。

三、根據上面的參數,以及handleSizeChangehandleCurrentChange這兩個函數的參數你就應該想到分頁的實現實際上是pageCode(當前頁)和pageSize(每頁顯示的記錄數)和後端進行數據交換的。在前端你須要關心的怎樣把pageSizepageCode傳給後端進行分頁查詢;在後端你須要關心的是怎樣調用pageHelper插件將分頁的記錄數據(包括totalPageuser數據等)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中定義的請求映射路徑,其中須要接收兩個參數:pageCodepageSize分別表示當前頁、每頁顯示的記錄數;即前端請求這個方法時只須要將pageCodepageSize傳進來就行,後端使用pageHelper分頁插件將查詢到的數據進行分頁,並將結果返回給前端。

對於請求映射中包含多個參數的,應該使用@RequestParam()進行標記,否則可能報錯400等。

<br/>

邏輯思路

後端

首先咱們須要定義分頁實體類:PageBean.java

public class PageBean() implements Serialization {
	//當前頁
    private long total;
    //當前頁記錄
    private List rows;
}

由於咱們使用了mybatis的分頁插件:PageHelper,因此PageHelper最終爲咱們封裝在PageBean的數據應該是這個樣子的:

**注意:**須要返回JSON格式數據。能夠看到裏面主要包含兩個參數:totalrows

  • 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.有哪些可能被觸發的事件和方法?

  • findByPage(pageCode,pageSize) 這個是分頁的核心方法,會被屢次觸發。又由於進入頁面就應該理解渲染表格中的數據,因此分頁方法應在渲染頁面時就執行,因此須要在created聲明周期函數中調用findByPage(this.pageConf.pageCode,this.pageConf.pageSize)(傳入默認的值)。對應的HTML代碼:
findByPage(pageCode, pageSize) {},
  • handleSizeChange(val) 這個函數是當pageSize(每頁顯示的記錄數)改變時被觸發,經過HTML中的@size-change屬性綁定。好比:原來4條/每頁改變爲6條/每頁,就將觸發這個函數;其中的參數val表示當前頁每頁顯示幾條記錄pageSize = val。對應的HTML代碼:
handleSizeChange(val) {
    this.findByPage(this.pageConf.pageCode, val);
},

每當pageSize改變就須要從新調用findByPage(this.pageConf.pageCode, val)函數從新計算頁面須要渲染的數據。

  • handleCurrentChange(val) 這個函數是當pageCode(當前頁)改變時觸發的函數,經過HTML中的@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方法請求後端獲得了totalrows,就應該分別賦值給this.pageConf.totalPagethis.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函數二者共同完成的分頁邏輯計算,其返回的數據主要是在totalrows中封裝着。

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.

相關文章
相關標籤/搜索