# VuePress Tutorial 16 - Pagination
# What We're Doing
Now it's time to learn more about the pagination feature and the Client API provided by @vuepress/plugin-blog (opens new window). In this tutorial we're going to begin the configuration of the pagination property as well as discuss the globally scoped $pagination variable provided by the Client API.
Make sure you start the local development server which should be running at http://localhost:8080/ (opens new window) to see the changes we'll be making to the site. If the changes aren't appearing after you save them, then try restarting your local development server.
You can view all of the code in this tutorial by going to the tutorial-16 branch of the code-monkeys-blog-tutorials (opens new window) repository.
# Pagination Configuration
As mentioned in the previous tutorial pagination allows you to break up the display of your posts into multiple pages. This provides easier navigation and a better user experience.
If you have any questions or want to learn more about the pagination configuration, then check out the pagination property (opens new window) and Pagination Config (opens new window) documentation.
# pagination
We're going to begin the configuration by adding the pagination property which allows you to customize the pagination of your posts.
The expected type is a Pagination object.
Here's the updated config.js file:
# lengthPerPage
Next, we'll add the lengthPerPage property which sets the maximum number of posts to display per page.
The expected type is a number, and the default value is 10.
When the number of posts is greater than the lengthPerPage value, the blog plugin will generate the necessary pages to display all of the posts.
The blog plugin does this by adding page/n/ onto the end of the entry page where n represents the number of the page.
So, the second page in the paginated list of pages would be page/2/.
If you remember from the previous tutorial VuePress Tutorial 15 - Blog Plugin, the entry page is set by the path property which was given a value of /posts/.
This means in our case the blog plugin will generate pages with the following format: /posts/page/n/ where n once again represents the number of the page.
We also created the following posts in the _posts directory in the previous tutorial:
2020-07-03-example-page-1.md2021-11-16-example-page-2.md2022-05-08-example-page-3.md
Since we only have three posts and the default value for lengthPerPage is 10, the blog plugin won't generate any more pages. You can test this by attempting to navigate to the following page:
To demonstrate the generation of pages we can set the lengthPerPage to have a value of 2.
Here's the updated config.js file:
You should now be able to navigate to the following page:
Updating lengthPerPage
In a future tutorial we'll be updating the value of lengthPerPage to be 5 which is the current value being used in the blog.
# layout
Now we're going to add the layout property which is used to specify which layout component to use for the pagination pages except for the entry page. The entry page uses the IndexPost layout component which we set in the previous tutorial.
The expected type is a string, and the default value is 'DirectoryPagination' || 'Layout'.
Since we haven't created a DirectoryPagination layout component in the layouts directory, the layout property uses the other default value which is the Layout component. In our case the Layout component is provided by the default theme (opens new window).
To see the difference between the layout of the entry page and the layout of the second page you can navigate to the following pages:
- http://localhost:8080/posts/posts/ (opens new window)
- http://localhost:8080/posts/page/2/ (opens new window)
If you want your pagination pages except for the entry page to use a layout specifically designed for them, then you can create a DirectoryPagination.vue file inside of the layouts directory. Since DirectoryPagination is the default value for the layout property you won't need to explicitly set it in the config.js file.
We'll be using the same layout for the entry page and for the other pagination pages, so we're going to provide a custom value of IndexPost to the layout property.
Here's the updated config.js file:
When navigating to the following page you should now see the IndexPost layout component being used instead of the Layout component:
Here's a table that summarizes the relationship between the pagination and post page URLs the blog plugin builds and the layout components:
| URLs | Layouts |
|---|---|
/posts/ | IndexPost (falls back to Layout) |
/posts/page/2/ | IndexPost (falls back to DirectoryPagination or Layout) |
/2020/07/03/example-page-1/ | Post |
/2021/11/16/example-page-2/ | Post |
/2022/05/08/example-page-3/ | Post |
Post Pages Reminder
The post pages were given the URLs above by building customized permalinks using the format specified by the itemPermalink property, and the layout components used by the post pages were set by the itemLayout property. Both of these properties can be found in the config.js file, and you can refer to the previous tutorial VuePress Tutorial 15 - Blog Plugin if you have any questions about the post pages.
# prevText
Now we'll add the prevText property which is used to specify the text for the previous links. The previous links are used to navigate to the previous page in the list of pagination pages.
The expected type is a string, and the default value is 'Prev'.
We'll be using the default value of 'Prev' for the prevText property, so we don't need to explicitly set the property. However, we're going to explicitly set it because this gives us a quick reference to the property and its value.
It's also possible to use a custom value for the prevText property, e.g., you could use a value of Older which you would have to explicitly set in the config.js file.
Here's the updated config.js file:
# nextText
We're now ready to add the nextText property which is used to specify the text for the next links. The next links are used to navigate to the next page in the list of pagination pages.
The expected type is a string, and the default value is 'Next'.
We'll be using the default value of 'Next' for the nextText property, so we don't need to explicitly set the property. However, we're going to explicitly set it because this once again gives us a quick reference to the property and its value.
It's also possible to use a custom value for the nextText property, e.g., you could use a value of Newer which you would have to explicitly set in the config.js file.
Here's the updated config.js file:
# Client API
We're now going to take a look at how to use the Client API to access the pagination data in the layout components used by the blog plugin.
The Client API uses globally scoped variables which means you can access these variables from any component as well as in Markdown files when using Vue. You can check out the Using Vue in Markdown (opens new window) documentation if you're interested.
The Client API provides the following globally scoped variables: $pagination, $frontmatterKey, and $service. We'll be focusing on the $pagination variable in this tutorial.
If you have any questions or want to learn more about the Client API, then check out the Client API (opens new window) documentation.
# $pagination
We're going to discuss each property the $pagination variable exposes as well as demonstrate how to access the properties in the layout components.
To get a better understanding of the pagination data we're going to log each property to the console. The logging will be added to the created lifecycle hook in the script tag. To view the data in the console we're going to inspect the browser then go to the Console tab.
If you have questions about the created lifecycle hook, then check out this resources:
null $paginaton
If you access the $pagination variable at a route which doesn't match any classification, i.e., the route isn't a pagination page, then the value of $pagination will be null.
This means when developing layout components you should check if $pagination has a value of null before using the variable.
# pages
The $pagination.pages property is an array of objects where each object contains data related to post pages that are accessible on the current pagination page.
Since the $pagination.pages property contains data related to post pages that are accessible on the current pagination page, the data of $pagination.pages will be different depending on which pagination page is being viewed.
To see the differences between the data, we're going to look at the entry page and the second page which in our case is also the last page.
Here are the links to both the entry page and the second page:
- http://localhost:8080/posts/ (opens new window)
- http://localhost:8080/posts/page/2/ (opens new window)
Let's add the code to log the $pagination.pages property in the layout component which in our case is being used by both the entry page and the second page, i.e., the IndexPost.vue file:
Using Different Layout Components
If you're using different layout components for your entry page and the other pagination pages, then you'll need to add the logging of the $pagination.pages property to both of the files.
After adding the above code to the IndexPost.vue file and navigating to the entry page, the console should log an array of page objects with the following data:
Since the lengthPerPage property was given a value of 2 and we have three post pages, the $pagination.pages property for the entry page contains two page objects one for each post.
Formatting Differences
The log in the Console tab will be formatted differently than the $pagination.pages data shown here which was formatted using JSON (opens new window). The properties and values will be the same though.
After navigating to the second page, the console should log an array consisting of one page object with the following data:
Now let's describe what each property in the $pagination.pages data represents:
frontmatter: Contains the data present in the frontmatter (opens new window) of the post pages.layout: Layout component used by the post pages which is set using theitemLayoutproperty in theconfig.jsfile.permalink: Permalink format used for the post pages which is set using theitemPermalinkproperty in theconfig.jsfile.id: Unique id for the current classifier which is set using theidproperty in theconfig.jsfile.key: Unique key generated for each page in the site.path: Path for the post page which uses a customized permalink built from the format specified by theitemPermalinkproperty found in theconfig.jsfile.pid: Represents the pid for the current classifier which is set using theidproperty in theconfig.jsfile.regularPath: Default path for the post page which is built using the:regulartemplate variable.relativePath: Location of the post page Markdown file relative to the documents directory which in our case is thedocsdirectory.
The $page Variable
The page objects in the $pagination.pages property are the same page objects found by logging the globally scoped $page variable in the Post layout component. After writing the code to log the $page variable, you can view the log by navigating to a post page, e.g., http://localhost:8080/2020/07/03/example-page-1/ (opens new window).
To learn more about the $page variable and other globally scoped variables you can take a look at the Global Computed (opens new window) documentation.
# length
The $pagination.length property is a number whose value is determined by the number of pagination pages.
Let's add the code to log the $pagination.length property in the IndexPost.vue file:
If we navigate to either the entry page or the second page, the console should log a value of 2 since in our case there are a total of two pagination pages.
# hasPrev
The $pagination.hasPrev property is a boolean which has a value of true when a previous pagination page exists and a value of false when a previous pagination page doesn't exist.
Let's add the code to log the $pagination.hasPrev property in the IndexPost.vue file:
If we navigate to the entry page, the console should log a value of false. This makes sense since the entry page is the first pagination page which means there is no previous pagination page.
If we navigate to the second page, the console should log a value of true which makes sense since the entry page is before the second page.
# prevLink
The $pagination.prevLink property is a string whose value is the previous pagination page path if a previous pagination page exists and a value of null when a previous pagination page doesn't exist.
Let's add the code to log the $pagination.prevLink property in the IndexPost.vue file:
If we navigate to the entry page, the console should log a value of null. This makes sense since the entry page is the first pagination page which means there is no link to a previous pagination page.
If we navigate to the second page, the console should log a value of /posts/ which makes sense since the previous link before the second page is the entry page which has a path of /posts/.
# hasNext
The $pagination.hasNext property is a boolean which has a value of true when a pagination page exists after the current pagination page and a value of false when a pagination page doesn't exist after the current pagination page.
Let's add the code to log the $pagination.hasNext property in the IndexPost.vue file:
If we navigate to the entry page, the console should log a value of true. This makes sense since there is a next page in the paginated list of pages, i.e., the second page.
If we navigate to the second page, the console should log a value of false which makes sense since in our case there is no pagination page after the second page.
# nextLink
The $pagination.nextLink property is a string whose value is the path of the next pagination page if it exists and a value of null when the next pagination page doesn't exist.
Let's add the code to log the $pagination.nextLink property in the IndexPost.vue file:
If we navigate to the entry page, the console should log a value of /posts/page/2/. This makes sense since the entry page is the first pagination page, and in our case there is a link to the next pagination page, i.e., the second page.
If we navigate to the second page, the console should log a value of null. This makes sense since in our case the second page is the last page in the list of pagination pages which means there is no link to the next pagination page.
# getSpecificPageLink()
The $pagination.getSpecificPageLink() is a method that accepts a page number and returns the path of a pagination page. The page numbers start at 0, so to get the entry page path you need to provide a value of 0. If an input is provided that is unable to return a path to a pagination page, then an error is thrown which can be found in the Console tab.
Let's add the code to log the output of the $pagination.getSpecificPageLink() method in the IndexPost.vue file:
Since we used a page number of 0 in the code above, the console should log a value of /posts/. This makes sense since a value of 0 refers to the entry page which has a path of /posts/.
If we want to get the path of the second page, then we can use a value of 1 as the page number, so the console should log a value of /posts/page/2/. This makes sense since a value of 1 refers to the second page which has a path of /posts/page/2/.
# Next Steps
In the next tutorial we'll begin the development of the IndexPost layout component which will involve using the $pagination variable provided by the Client API.