태그를 기반으로 관련 기사를 가져오는 아스트로

17803 단어 astro
각 게시물 하단에 관련 기사를 소개했습니다.

이들은 가장 근접하게 일치하는 태그를 기반으로 하며, 이 기사에서는 Astro에서 이를 재생성하는 방법을 설명합니다.



관련 기사 검색



가장 먼저 할 일은 간단한 사용 사례를 만드는 것입니다. 최신 기사 두 개를 보여드리고자 합니다.

구성 요소 디렉터리에 RelatedArticles.astro라는 구성 요소를 만듭니다.

Frontmatter 섹션에서는 먼저 모든 게시물을 로드합니다.fetchContent는 무한 루프를 일으키기 때문에 여기에서 작동하지 않는다는 점에 유의하는 것이 중요합니다.

---
const fetchedPosts = await import.meta.glob("../pages/posts/*.md");
const allPosts = await Promise.all(
    Object.keys(fetchedPosts).map((key) => {
      const post = fetchedPosts[key];
      const url = key.replace("../pages/", "/").replace(".md", "/");
      return post().then((p) => {
        return { ...p.frontmatter, url };
      });
    });
);
---


그런 다음 현재 기사를 표시하지 않도록 하고 날짜를 기준으로 정렬합니다.

// Retrieve the props from the component
const { tags, currentPathname } = Astro.props;

const mappedTags = allPosts
  .filter(({ url }) => url !== currentPathname)
  .filter((a) => new Date(a.date) <= new Date())
  .sort((a, b) => new Date(b.date) - new Date(a.date));


그런 다음 HTML 섹션에서 두 가지를 반환할 수 있습니다.

<div class="container md:mx-auto">
  <div class="mx-0 md:-mx-4 grid grid-cols-1 md:grid-cols-2">
    <article article="{mappedTags[0]}" />
    <article article="{mappedTags[1]}" />
  </div>
</div>


참고: 저는 제가 만든 기존Article 구성 요소를 사용하고 있습니다. 귀하의 구성 요소는 다르게 보일 수 있습니다.

이제 관련 기사를 게시물 템플릿에 추가할 수 있습니다.

<RelatedArticles tags={content.tags} currentPathname={canonicalURL.pathname} />


현재 게시물의 태그와 사용자가 있는 페이지의 현재 경로 이름을 전달합니다.

내 것을 복사 관련 기사 순위



스크립트가 준비되었으므로 마지막 두 기사가 표시되지만 주로 서로 관련이 없을 수도 있습니다.

몇 가지 규칙을 생각해 냈고 다음과 같은 순서가 되어야 합니다.
  • 모든 태그 일치
  • 일부 태그 일치
  • 하나의 태그가 일치합니다
  • 일치하는 태그가 없습니다.

  • 이 모든 것은 이미 날짜를 기반으로 하므로 최신 기사와 일치시킵니다.

    내 태그는 다음과 같이 보일 수 있는 내 마크다운의 주요 섹션입니다.

    ---
    layout: ../../layouts/Post.astro
    ...
    tags:
      - developer
      - javascript
      - css
    ---
    


    물론 기사에 이러한 태그가 모두 있으면 완벽하게 일치하므로 먼저 표시해야 합니다.

    이 시점에서 나는 이것이 설정하기 꽤 힘든 일이라는 것을 깨달았고 실제 예제가 있었지만 약간 보기 흉했습니다.
    그래서 친구에게 조언을 구하기로 했습니다.

    그는 완벽하게 작동하는 것으로 판명 된 미친 솔루션을 생각해 냈습니다!

    가장 먼저 할 일은 각 기사의 모든 태그를 일치시키는 것입니다.
    필터 및 정렬 설정이 이미 있으므로 여기에 축소를 추가할 수 있습니다.

    const mappedTags = allPosts
      .filter(({ url }) => url !== currentPathname)
      .filter((a) => new Date(a.date) <= new Date())
      .sort((a, b) => new Date(b.date) - new Date(a.date))
      .reduce(
        (filtered, article) => {
          // TODO
        },
        { all: [], some: [], one: [], none: [] }
      );
    


    무슨 일이 일어나고 있는지 눈치채셨을 것입니다. 아시다시피, 누산기와 현재 값이 있습니다.
    기본값으로 계산하려는 유형이 있는 객체에 값을 설정합니다.

    가장 먼저 해야 할 일은 축소된 기사의 태그가 페이지의 태그와 일치하는지 계산하는 것입니다.

    우리가 구현한 이 기능을 통해 게시물 태그에 액세스할 수 있음을 기억하십시오.

    const { tags, currentPathname } = Astro.props;
    



    const mappedTags = allPosts
      .filter(({ url }) => url !== currentPathname)
      .filter((a) => new Date(a.date) <= new Date())
      .sort((a, b) => new Date(b.date) - new Date(a.date))
      .reduce(
        (filtered, article) => {
          // nice use of type coercion: true => 1, false => 0, so we can add a boolean to number here
          const foundTagsCount = tags.reduce(
            (count, tag) => count + article.tags.includes(tag),
            0
          );
        },
        { all: [], some: [], one: [], none: [] }
      );
    


    솔직히 말해서, 저는 이것이 Alex의 약간의 마술임을 발견했습니다. 우리는 또 다른 reduce를 사용하지만 여기에 일치하는 태그의 수를 합산합니다.

    결국 reduce는 원본 기사와 일치하는 태그의 수입니다.

    그런 다음 금액이 맞는 범주를 정의해야 하므로 foundTagsCount , all , some 또는 one 중 하나가 될 수 있습니다.

    const amount =
      tags.length === foundTagsCount
        ? 'all'
        : foundTagsCount > 1
        ? 'some'
        : foundTagsCount
        ? 'one'
        : 'none';
    


    따라서 모든 태그와 일치하면 none 로 푸시합니다. 개수가 모두 일치하지 않고 둘 이상인 경우 all 등으로 푸시합니다.

    그런 다음 이를 기본 reduce 함수의 누산기 값으로 푸시해야 합니다.

    filtered[amount].push(article);
    return filtered;
    


    우리는 각 카테고리의 모든 기사와 일치하는 깔끔한 배열을 얻었습니다.

    그리고 우리는 그것들을 하나의 큰 배열로 분산시키고 당신이 보여주고 싶은 첫 x개의 양을 취할 수 있습니다.

    const { all, some, one, none } = mappedTags;
    const output = [...all, ...some, ...one, ...none];
    

    some 변수는 제 경우에 처음 2개를 사용하기 위해 퍼진 순서대로 됩니다.

    <div class="container md:mx-auto">
      <div class="mx-0 md:-mx-4 grid grid-cols-1 md:grid-cols-2">
        <article article="{output[0]}" />
        <article article="{output[1]}" />
      </div>
    </div>
    


    꽤 도전적이지만 태그를 기반으로 몇 가지 멋진 권장 사항을 만들었습니다.
    앞으로 여기에 필터링 옵션을 더 추가할 수도 있지만 현재로서는 원하는 것과 비슷해 보입니다.

    산출 읽어주셔서 감사합니다. 연결해 보겠습니다!



    제 블로그를 읽어주셔서 감사합니다. 내 이메일 뉴스레터를 구독하고 또는

    좋은 웹페이지 즐겨찾기