# VuePress Tutorial 16 - Pagination

By: Jay the Code Monkey
Posted: Sep 30, 2022 Updated: Apr 18, 2023

# 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:

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:

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 the itemLayout property in the config.js file.
  • permalink: Permalink format used for the post pages which is set using the itemPermalink property in the config.js file.
  • id: Unique id for the current classifier which is set using the id property in the config.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 the itemPermalink property found in the config.js file.
  • pid: Represents the pid for the current classifier which is set using the id property in the config.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 the docs 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.

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.

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.

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.

Made by & for Code Monkeys 🐵