用nextjs给掘金的读者发制作徽章墙(0.1版)--4/1000

我是天元,立志做1000个有趣的项目的前端,公众号:cssandjs

如果你喜欢的话,请点赞,收藏,转发

评论领取创始者勋章

背景

最近掘金的每篇文章,我都在顶部写了领取xx徽章,其实这就是我早就想好的,我要制作一个徽章墙给所有评论的人。

目前因为自己的域名备案还没通过,所以只能烦请各位大老爷自己运行下代码

现在已经迭代到0.1版本,目前效果如下。

github地址:github.com/tinlee/1000...

需求分析

  • 目前域名备案还没下来,所以目前一切从简。
  • 第一个版本,以快速为主,所以直接使用文件做存储,第二个版本再做数据库
  • 需要一个获取掘金评论数据的接口
  • 需要一个展示勋章的页面
  • 因为同时需要接口和页面,所以采用nextjs作为框架,同时保证了前后端的需求

徽章的生成

推荐使用scenario.com来生成,是专门做游戏素材的ai生成网站。

编码部分

安装

请按照nextjs.org上的方法进行项目相关的安装和初始化,中文版的略微滞后,有break change

bash 复制代码
npx create-next-app@latest

这里的安装按照个人喜好就可以了。

bash 复制代码
yarn add axios
yarn dev

安装axios并启动项目

资源放置

在public中建立badge文件夹,放置徽章相关资源。 同时新建一个database文件夹,用于放置数据相关资源。因为涉及到具体用户的信息,这里放置后,请求比较方便。

新建articel.json,放置我们的文章及徽章相关信息。

json 复制代码
[
  {
    "url": "https://juejin.cn/post/7347910198784999461",
    "name": "父爱如山",
    "icon": "father.png"
  },
  {
    "url": "https://juejin.cn/post/7346421986607087635",
    "name": "零花钱+100",
    "icon": "gold.png"
  },
  {
    "url": "https://juejin.cn/post/7348327193061507108",
    "name": "早发现早治疗",
    "icon": "treat.png"
  },
  {
    "url": "https://juejin.cn/post/7353106546828460047",
    "name": "永不言败",
    "icon": "phoenix.png"
  }
]

这里是我的4篇文章,列举了徽章所需的文章地址,徽章名称以及图案信息。

新建请求接口

nextjs既可以使用一个react组件作为页面显示,也可以使用接口模式,建立一个接口。

src/app下新建spider/route.js

js 复制代码
import { NextResponse } from "next/server";
import axios, { AxiosResponse } from "axios";
import fs from "fs";


export async function GET(request, context) {
 
  return NextResponse.json(
    { data: 'its test'},
    { status: 200 }
  );
}

访问http://localhost:3000/spider,这个页面就是我们获取掘金数据的接口了。

理解掘金数据获取规则

我们在掘金中点击查看全部评论的时候,会请求一个接口 这个接口就是获取评论的接口,它本身是分页加载的,因为我们是披露获取的,所以我们把cursor改成0,把limit改成999

route.js进行补充

js 复制代码
import { NextResponse } from "next/server";
import axios, { AxiosResponse } from "axios";
import articels from "../../../public/database/articel.json";
import fs from "fs";

function getPromise({ url }) {
  const itemId = url.split("/").pop(); // 获取文章itemId
  return axios.post("https://api.juejin.cn/interact_api/v1/comment/list", {
    item_id: itemId,
    item_type: 2,
    cursor: "0",
    limit: 999,
    sort: 0,
    client_type: 2608,
  });
}

export async function GET(request, context) {
  const promise = articels.map(getPromise); // 构建所有文章的请求
  const res = await Promise.all(promise);

  // 因为一个用户可以存在多个徽章,所以这里用一个map接收
  const user = {};
  // 遍历请求数据并将结果和徽章信息绑定
  res.forEach((item, index) => {
    const { icon, name } = articels[index];
    item.data.data.forEach((subitem) => {
      const { user_info, comment_info } = subitem;
      const { ctime } = comment_info;
      const { user_name, user_id, job_title, company, avatar_large } =
        user_info;

      if (!user[user_id]) {
        user[user_id] = {
          user_name,
          ctime,
          user_id,
          job_title,
          company,
          avatar_large,
          badges: [{ icon, name }],
        };
      } else {
        user[user_id].badges.push({ icon, name });
      }
    });
  });

  // 在写入的时候,对用户进行排序
  fs.writeFileSync(
    "./public/database/user.json",
    JSON.stringify(Object.values(user).sort((a, b) => b.ctime - a.ctime))
  );

   return NextResponse.json({ data: "获取成功" }, { status: 200 });

}
  • public/database/articel.json获得文章数据
  • 分割url获取itemId,并构建请求
  • 将所有请求数据进行提取,构建页面所需的数据
  • 将数据按照评论时间排序并保存到database/user.json

至此相关的数据准备已经就绪了,我们最终形成了如下的数据结构

这里的badges是一个数组,用于一个用户多次评论的场景

构建展示页面

修改 展示页面根据自己的喜好即可,唯一需要注意的是数据的请求地址

js 复制代码
  axios.get("/database/user.json")

这里的数据也可以使用fs去读取,但是考虑之后我会将数据入库和分页,所以这里直接用了请求。相关代码如下: src/app/page.js

js 复制代码
"use client";
import styles from "./page.module.css";
import axios from "axios";
import { useEffect, useState } from "react";
export default function Home() {
  const [user, setUser] = useState([]);
  useEffect(() => {
    axios.get("/database/user.json").then((res) => {
      setUser(Object.values(res.data));
    });
  }, []);

  return (
    <div className={styles.container}>
      {user.map((item) => {
        return (
          <div key={item.user_id} className={styles.user}>
            <div className={styles.header}>
              <div className={styles.headerImage}>
                <img src={item.avatar_large} />
              </div>
              <div className={styles.userName}>{item.user_name}</div>
              <div className={styles.job}>
                {[item.job_title, item.company]
                  .filter((item) => item)
                  .join("@")}
              </div>
            </div>
            <div className={styles.badges}>
              {item.badges.map((bg, ind) => {
                return (
                  <div key={ind} className={styles.badgesItem}>
                    <img src={"/badge/" + bg.icon} />
                    <span className={styles.badgesName}>{bg.name}</span>
                  </div>
                );
              })}
            </div>
          </div>
        );
      })}
    </div>
  );
}

page.module.css

css 复制代码
.container {
  margin: 0 auto;
  max-width: 680px;
  padding: 20px;
  font-size: 14px;
}
.user {
  padding: 16px;
  margin: 16px 0;
  border-radius: 6px;
  border-bottom: 1px solid #ccc;
  background: #fff;
  border: 1px solid rgb(208, 215, 222);
  box-shadow: rgba(31, 35, 40, 0.04) 0px 1px 0px 0px;
}
.header {
  display: flex;
  align-items: center;
  padding-bottom: 16px;

  color: color rgb(31, 35, 40);
}
.headerImage {
  width: 40px;
  height: 40px;
  border-radius: 20px;
  overflow: hidden;
  margin-right: 8px;
}
.headerImage img {
  width: 100%;
  height: 100%;
  display: block;
}
.userName {
  font-weight: 400;
  line-height: 36px;
  padding-right: 8px;
}
.job {
  color: rgb(99, 108, 118);
}

.badges {
  display: flex;
  background-color: rgb(246, 248, 250);
  padding: 16px;
}
.badgesItem {
  margin-right: 20px;
}
.badgesItem img {
  width: 60px;
  height: 60px;
  display: block;
}
.badgesName {
  text-align: center;
  color: rgb(31, 35, 40);
  display: block;
  padding-top: 8px;
}

最终效果

todolist

  • 数据入库
  • 文章新增接口,徽章管理
  • 展示页面分页加载和搜索
  • 服务器部署和cdn

我是天元,立志做1000个有趣的项目的前端,公众号:cssandjs

如果你喜欢的话,请点赞,收藏,转发

评论领取永不言败勋章

历史文章

相关推荐
hunter2062061 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb1 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角1 小时前
CSS 颜色
前端·css
浪浪山小白兔2 小时前
HTML5 新表单属性详解
前端·html·html5
lee5763 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
2401_897579653 小时前
AI赋能Flutter开发:ScriptEcho助你高效构建跨端应用
前端·人工智能·flutter
光头程序员3 小时前
grid 布局react组件可以循数据自定义渲染某个数据 ,或插入某些数据在某个索引下
javascript·react.js·ecmascript
limit for me3 小时前
react上增加错误边界 当存在错误时 不会显示白屏
前端·react.js·前端框架
浏览器爱好者3 小时前
如何构建一个简单的React应用?
前端·react.js·前端框架
qq_392794484 小时前
前端缓存策略:强缓存与协商缓存深度剖析
前端·缓存