Архив блога на JavaScript?

#javascript #reactjs

Вопрос:

Я хочу, чтобы в моем блоге была страница архива, которая выглядела бы так (проверьте под заголовком Все статьи по дате) с одним годом вверху, затем месяцем и датой с названием статьи под ним.

У меня есть массив сообщений с типом Meta , который выглядит так:

 export type Meta = {
    title: string
    date: Date
    lastEdited?: Date
    description: string
    slug: string
    tags: Array<Tag>
    image?: string
    author: string
    isPublished?: Boolean
}
 

И я заставил это работать, но в результате year оказался рядом, используя:

 import React from 'react'

import { getYearMonthDate } from '@/utils/index'

import type { Meta } from '@/types/index'

export const Archive = ({ tutorials }: { tutorials: Meta }) => {
    return (
        <ul>
            {tutorials.map((tutorial: Meta) => {
                const [year, month, date] = getYearMonthDate(tutorial.date)
                let archiveYear
                return (
                    <li key={tutorial.slug}>
                        <h3 className="archiveYear">{year}</h3>
                        <span className="archiveDay">
                            {month} {date}
                        </span>
                        <a className="archiveLink">{tutorial.title}</a>
                    </li>
                )
            })}
        </ul>
    )
}
 

Я знаю, что мне нужно использовать цикл for и отслеживать старый год, сравнивать его с новым и использовать массив для передачи данных, но это приведет к уродливой HTML-разметке.

Есть ли какой-нибудь способ сделать так, чтобы это выглядело как желаемый результат. Если да, то как мне это сделать?

Комментарии:

1. Я не совсем понял вопрос, но вместо этого использовал hashmap?

Ответ №1:

Я заставил его работать с помощью Map . Во-первых, я использовал for цикл и поместил данные своего блога в a Map в формате year as key amp; post[] as value .

utils/index.ts

 import { format, parseISO, getYear as gY, getDate as gD } from 'date-fns'

export const formatDate = (date: string) => format(parseISO(date), 'MMMM dd, yyyy')

export const getYear = (date: Date) => gY(new Date(date))
export const getMonth = (date: Date) => format(new Date(date), 'MMMM')
export const getDate = (date: Date) => gD(new Date(date))
 

Архив,tsx

 import React from 'react'
import Link from 'next/link'

import { getYear, getMonth, getDate } from '@/utils/index'

import type { Meta } from '@/types/index'

export const Archive = ({
    postType,
    posts,
}: {
    postType: 'essay' | 'tutorial' | 'snippet'
    posts: Meta[]
}) => {
    const archive = new Map()
    for (let i = 0; i < posts.length; i  ) {
        const post: Meta = posts[i]
        const year = getYear(post.date)
        if (!archive.has(year)) {
            archive.set(year, [post])
        } else {
            const oldArchive = archive.get(year)
            archive.set(year, [...oldArchive, post])
        }
    }

    return (
        <ul className="grid grid-cols-[1fr,min(90ch,calc(100%-64px)),1fr] gap-8 archive mb-64">
            {Array.from(archive.entries()).map(([archiveYear, posts], i) => {
                return (
                    <li key={i}>
                        <h3 className="text-3xl font-bold archiveYear">{archiveYear}</h3>
                        {posts.map((post: Meta) => {
                            const month = getMonth(post.date)
                            const date = getDate(post.date)
                            return (
                                <div
                                    className="grid grid-cols-[144px,calc(100%-144px)] my-2 text-lg font-medium"
                                    key={post.slug}
                                >
                                    <span className="text-gray-700 archiveDay dark:text-gray-300">
                                        {month} {date}
                                    </span>
                                    <Link href={`/${postType}/${post.slug}`}>
                                        <a className="text-gray-700 dark:text-gray-300 archiveLink">{post.title}</a>
                                    </Link>
                                </div>
                            )
                        })}
                    </li>
                )
            })}
        </ul>
    )
}