# 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.md
2021-11-16-example-page-2.md
2022-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 theitemLayout
property in theconfig.js
file.permalink
: Permalink format used for the post pages which is set using theitemPermalink
property in theconfig.js
file.id
: Unique id for the current classifier which is set using theid
property in theconfig.js
file.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 theitemPermalink
property found in theconfig.js
file.pid
: Represents the pid for the current classifier which is set using theid
property in theconfig.js
file.regularPath
: Default path for the post page which is built using the:regular
template variable.relativePath
: Location of the post page Markdown file relative to the documents directory which in our case is thedocs
directory.
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.