background
Recently, the company’s background wanted to change the current background management system, saying that the previous one was too ugly, and it was not easy to use. Then he sent me an ant-design-pro link, saying that it was good for him to see it.
I thought to myself, the previous project was mixed in with your Java project, which looks like a normal JSP page, with a bunch of CSS and JS files that I’m scared to see (ok, I admit I can’t even look at it), and it’s amazing how fast it loads. The Ant-Design interface was originally designed for React, and the Ant-Design-Pro was also designed for React, so I have to say the interface looks really comfortable.
I read the official document of Ant-Design-Pro, and it looks like I just didn’t read it. You can use dVA to manage your state except react + React-router. You can use dVA to manage your state except react + React-router.
Wait, what am I missing? The largest js file is over 900 K. The source file of Ant design is really big. React I can only write code, packaging optimization this can be a bit difficult for me. At this time I again think of the company that 1m bandwidth, as well as the technical capability of these several background, or I still give up this technology stack? Can’t expect even request header, CORS slightly advanced carry cookie, nGINx static server all don’t understand the people to give me a static server, and open gzip by the way? Look for the vue + element-ui background template. You can find the vue-element-admin template without too much effort.
Vue-element-admin worked fine, but the interface didn’t quite match my ideal, so I changed it a bit to Ant-Design-Pro, and the list page looks like this. The data of the list should be paged. The normal list page has only one page stack, that is, when the user clicks on the address bar to roll back the address bar, the data of the previous page will be returned, not the data of the previous page, which is not quite consistent with the user’s habit, right? After all, the traditional website can go back to the previous page, well, no more words, let’s get to the point.
Step 1: Change the address bar
Suppose the list page path is /user/list, and the page-related parameters are {page: 1, pagesize: 10}, the path to another page usually contains no parameters, and the list data is changed according to the page and pagesize of the page. When the keep-alive component is not used, every entry to the list page is the first entry. This means that only the first page of data can be retrieved at a time.
Since page and pagesize are used for table data, why not just get page and pagesize from the address bar and assign them? Is the code that changes the address bar written directly on the current page or is it a separate pagination component? In terms of reuse, it is better to be independent, after all, other pages may also be used, can’t copy and paste it every time, then what is the significance of componentization? Of course, you don’t have to use this custom pagination component for pagination, only when you need pagination on the home page (not the mask layer, but when you click on a row of data and the mask layer displays the sublist, you can use the element-UI pagination component).
When changing the address bar, we don’t want the stack to exist without paging, so use replace to replace.
The initial structure of mypagination. vue is:
<template>
<div class = " flex all-center">
<template v-if="total > 0">
<el-pagination
:page-size="pagesize"
:total="total"
:current-page="page"
background
layout="prev, pager, next, jumper, total"
class="my-pagination"
@current-change="changePage" />
</template>
</div>
</template>
<script>
export default {
name: 'MyPagination',
props: {
total: {
type: Number,
default: 0,
},
page: {
type: Number,
default: 1,
},
pagesize: {
type: Number,
default: 10,
},
totalPages: {
type: Number,
default: 1,
},
},
created() {
this.getCurrentPage();
},
methods: {
changePage(val) {
this.handlePage('push', val, this.pagesize);
this.$emit('change', val, this.pagesize);
},
getCurrentPage() {
var { page, pagesize } = this.$route.query;
if(! page || ! pagesize) { this.handlePage('replace', page || 1, +pagesize || this.pagesize);
return true;
}
return false;
},
handlePage(type, page, pagesize) {
this.$router[type]({
path: this.$route.path, query: { ... this.$route.query, page, pagesize }, }); } }, } </script> <! -- Add"scoped" attribute to limit CSS to this component only -->
<style scoped>
.my-pagination {
padding-top: 24px;
}
</style>
Copy the code
Key code for the parent component:
<MyPagination :total = "total" :pagesize = "pagesize" :page="page" :totalPages = "totalPages" @change = "changePage" />
methods: {
changePage(page, pagesize) {
var _page = this.page,
_pagesize = this.pagesize;
this.page = page;
this.pagesize = pagesize;
if(page ! == _page && pagesize || _pagesize ! == pagesize) this.fetchData(); // Do not retrieve paging data the first time you enter the page, because it is already obtained once in the created hook. }},Copy the code
Effect: When entering the page for the first time, if there is no paging parameter, the paging parameter will be changed first, and then the data will be obtained. After clicking the page number of the paging component, the data after the paging will also be obtained.
Step 2: Observe route changes
The implementation of the previous step may look like nothing wrong at first, but if you change the address bar directly, neither the current page nor the current data will be displayed. The front-end route will not be reloaded by default when the query parameters of the page change, unless the key of the page changes. This is to prevent the page from being rerendered as much as possible, so the key is not used to solve this problem. The change of $route is detected directly through VUE’s Watch, so as to change the display problem of the current page and current data.
Added to mypagination. vue:
watch: {
'$route'(to, from) {
let { page, pagesize } = to.query;
if(! this.getCurrentPage()) { this.$emit('change', +page || 1, +pagesize || 10); }}},Copy the code
Step 3: Control the size of pagesize
In the effect of the previous step, when you change the page and pagesize of the address bar, the data for the list page changes as well. Since it’s based on the address bar parameters, a new problem arises,
What if the user enters more pages than the total number of pages?
At this time, it mainly depends on how the backstage design,
- Returns the data from the first page.
getCurrentPage() {
var { page, pagesize } = this.$route.query; /* (totalPages > 0 && (page > totalPages)); If the total number of pages is greater than 0 and the current page is greater than the total number of pages, skip to the first page */if(! page || ! pagesize || (totalPages > 0 && (page > totalPages))) { this.handlePage('replace', page || 1, this.pagesize);
return true;
}
return false;
},
Copy the code
- Return the data from the last page (which I think is reasonable).
getCurrentPage() {
var { page, pagesize } = this.$route.query,
MAX_PAGESIZE = this.max,
totalPages = this.totalPages;
if(! page || ! pagesize) { this.handlePage('replace', page || 1, +pagesize || this.pagesize);
return true;
} else if (totalPages > 0 && (page > totalPages)) {
this.handlePage('replace', totalPages, +pagesize);
return true;
}
return false;
},
Copy the code
In place of the current stack, return true is used to block subsequent operations in the watch and cancel the request. After replacing the page, request the remote data and update the display of the current page and data.
- Return an empty array. (This is probably how most backends are designed. They don’t expect pages to be larger than the total number of pages.) The code is the same as in 2.
The above is based on the totalPages determined situation, if the page is the first time the situation will be different.
If the page is displayed for the first time, totalPages will be 0 the first time, and the address bar parameters will not change. In this case, the address bar and the paging component will be displayed inconsistently. Watch the change of totalPages in the pagination component.
totalPages(newVal, oldVal) {
if (+oldVal === 0 && newVal > 0) {
this.handlePage('replace', this.page, +this.pagesize); }}Copy the code
What if pagesize is too big?
Pagesize must be limited; if it is too large, querying data in the background can be slow and potentially stressful. The solution is as simple as adding a Max attribute to the props function, and then limiting it to getCurrentPage.
props: {
max: {
type: Number,
default: 20,
},
},
methods: {
getCurrentPage() {
var { page, pagesize } = this.$route.query,
MAX_PAGESIZE = this.max,
totalPages = this.totalPages;
if(! page || ! pagesize) { this.handlePage('replace', page || 1, +pagesize || this.pagesize);
return true;
} else if (pagesize > MAX_PAGESIZE) {
this.handlePage('replace', page, MAX_PAGESIZE);
return true;
} else if (totalPages > 0 && (page > totalPages)) {
this.handlePage('replace', totalPages, +pagesize);
return true;
}
return false; }},Copy the code
Step 4: Optimize your code
Two requests are made when the page number of the paging component is clicked
When clicking on a paging component, 1. It listens for a current-change event and changes the address bar, and emits a change event to the parent component. 2. However, after the address bar is changed, watch $route will emit change event to parent component, so only need to merge the change event emit change event, that is, current-change event only change address bar.
changePage(val) {
this.handlePage('push', val, this.pagesize);
},
Copy the code
The results of
At this point, a custom paging component has been implemented, changing the address bar parameters to see the paging data change, clicking the page number will change the address bar, and the number of requests has been reduced as much as possible.
Custom pagination component: mypagination.vue
List page: list.vue
Complete demo: front_end
If there are any questions, welcome to leave a message to discuss.