81
loading...
This website collects cookies to deliver better user experience
url/?page=1
url/page/${pageNumber}
-pages
--pages
---_page.vue // or anything else like _pageNumber.vue
<script>
export default {
async asyncData({ $content, params }) {
console.log(params.page) // a page number
}
}
</script>
nuxt-content
it can be achieved simply with limit()
& skip()
<script>
export default {
async asyncData({ $content }) {
const posts = await $content('posts')
.only(['title', 'description', 'createdAt', 'slug'])
.sortBy('createdAt', 'desc')
.skip(5) // number of posts to skip
.limit(5) // limit the number of posts to display
.fetch()
return { posts }
},
}
</script>
<script>
export default {
async asyncData({ $content, params, $config }) {
const totalPosts = (await $content('posts').fetch()).length
const currentPage = params.page ? +params.page : 1 // it is a string, convert to number
const perPage = $config.perPage
const lastPage = Math.ceil(totalPosts / perPage)
const lastPageCount =
totalPosts % perPage !== 0 ? totalPosts % perPage : totalPosts - perPage
const skipNumber = () => {
if (currentPage === 1) {
return 0
}
if (currentPage === lastPage) {
return totalPosts - lastPageCount
}
return (currentPage - 1) * perPage
}
const posts = await $content('posts')
.only(['title', 'description', 'createdAt', 'slug'])
.sortBy('createdAt', 'desc')
.skip(skipNumber())
.limit(perPage)
.fetch()
return { posts, totalPosts, currentPage, lastPage }
},
}
</script>
pages/index.vue
already have what we want. So I just copied the template. While it can be extracted into a separate component, in this particular case, I don't see myself updating it any time soon.<template>
<ul class="divide-y divide-gray-300 -mt-10 dark:divide-gray-400">
<li v-for="post in posts" :key="post.title" class="py-14">
<AppPostCard :post="post" />
</li>
</ul>
</template>
/pages/1
or /pages/2
, the list of posts will change accordingly. Simple navigation between pages can be added.<template>
<ul class="divide-y divide-gray-300 -mt-10 dark:divide-gray-400">
<li v-for="post in posts" :key="post.title" class="py-14">
<AppPostCard :post="post" />
</li>
<div class="flex justify-between py-5 text-yellow-500">
<button
class="flex space-x-4"
:class="{ 'text-gray-200': currentPage === 1 }"
@click="newer()"
>
← Newer
</button>
<button
class="flex space-x-4 float-right"
:class="{ 'text-gray-200': currentPage === lastPage }"
@click="older()"
>
Older →
</button>
</div>
</ul>
</template>
<script>
export default {
// retrieving posts
methods: {
newer() {
if (this.currentPage > 1) {
this.currentPage = this.currentPage - 1
}
if (this.currentPage > 1) {
this.$router.push({ path: `/pages/${this.currentPage}` })
} else {
this.$router.push({ path: '/' })
}
},
older() {
if (this.currentPage < this.lastPage) {
this.currentPage = this.currentPage + 1
}
this.$router.push({ path: `/pages/${this.currentPage}` })
},
},
}
</script>
pages/index.vue
view instead of /pages/1
to keep consistency when moving back and forth./pages
it will throw a "Not Found" error. It would be a much better experience if a user is redirected to a home page where the latest posts are..<script>
export default {
middleware({ redirect }) {
return redirect('301', '/')
},
}
</script>
<template>
<ul class="divide-y divide-gray-300 -mt-10 dark:divide-gray-400">
<li v-for="post in posts" :key="post.title" class="py-14">
<AppPostCard :post="post" />
</li>
<div class="flex justify-between py-5 text-yellow-500">
<button class="flex space-x-4 text-gray-200">← Newer</button>
<NuxtLink to="/pages/2">
<button class="flex space-x-4 float-right">Older →</button>
</NuxtLink>
</div>
</ul>
</template>
<script>
export default {
async asyncData({ $content }) {
const posts = await $content('posts')
.only(['title', 'description', 'createdAt', 'slug'])
.sortBy('createdAt', 'desc')
.limit(process.env.PER_PAGE)
.fetch()
return { posts }
},
}
</script>
limit()
to retrieve only the latest posts. Another thing to point out is that I have hardcoded the next page, as it will always be page number 2, so nothing fancy is required.nuxt generate
command is run now, there will be a few small problems:const createSitemapRoutes = async () => {
const routes = []
const { $content } = require('@nuxt/content')
const posts = await $content('posts').fetch()
for (const post of posts) {
routes.push(`/${post.slug}`)
}
const totalPosts = posts.length
const lastPage = Math.ceil(totalPosts / process.env.PER_PAGE)
for (let i = lastPage; i > 1; i--) {
routes.push(`/pages/${i}`)
}
return routes
}
export default {
// other configs
generate: {
async routes() {
return await createSitemapRoutes()
},
},
}
.PER_PAGE
variable. It is a simple global variable that will control the number of posts per page.