写个博客吧(根据标签分类与仿dev.to的面包屑实现)

mac2025-12-19  4

前言

之前基本完成了列表页和详情页的构建,接着构建一下根据标签显示列表的功能,以及头部组件的跳转,面包屑等逻辑的实现等,因为一些点击动画还没有想好怎么实现更好,这里先没有管,再看看medium等网站的交互逻辑再说吧。

接口

还是因为next.js的缘故,前台的动态路由都是用query的形式完成,但是对于后端接口就无所谓了,使用 param写起来很简单,所以我们类似于id选择文章接口实现以下即可:

@Get('list/:tags') @ApiOperation({title: '根据文章类别筛选列表'}) async getPostListByTag(@Param('tags') tags: string ) { // 使用query也可以 return await PostModel.find({tags: `${tags}`}) }

axios

开始我想使用.all方法在index界面就完成所有的功能,后来觉得写起来还是有些麻烦的,而且具体可不可行其实我也犯嘀咕,因为获取的数据是取代的关系而不是并列的关系,后来想既然这样不如用三元表达式筛选一下:

Home.getInitialProps = async(ctx) => { const res = ctx.query.tags ? await axios.get(api_url + `/list/${ctx.query.tags}`) : await axios.get(api_url) console.log({ data: res.data, ctx: ctx.query.tags }); return { data: res.data, ctx: ctx.query.tags } }

当得到tags的时候我们就得到了根据标签分类得到的文章列表,逻辑是没问题的,实现上也没有什么漏洞,但是不知道其他人是怎么实现这个功能的,自己感觉这里可能会牵扯一些性能问题,或者有更好的实现。

但是目前这样做是完全可以完成需要的逻辑的。

Head Tag

因为没有设置面包屑,所以我想起来 dev.to 设置的相关功能,诸如点击react标签,他会如下显示: 我个人也比较喜欢这种实现方式,于是上文我把ctx也传过去,为的就是方便添加这个HeadTag:

{ctx ? <TagContext.Provider value={ctx}> <HeadTag /> </TagContext.Provider> : <div></div> }

然后设计了一个小逻辑,用来根据ctx的内容判断HeadTag的具体内容:

const HeadTag = () => { const ctx = useContext(TagContext) return ( <div className='headTag'> <img src={techSymbol(ctx)} alt={ctx} className='headTag_img'/> <p className='headTag_font'>{ctx.toUpperCase()}</p> </div> ) } export const techSymbol = (ctx) => { switch(ctx) { case 'react': return 'https://res.cloudinary.com/practicaldev/image/fetch/c_scale,fl_progressive,q_auto,w_180/f_auto/https://thepracticaldev.s3.amazonaws.com/uploads/badge/badge_image/26/react-sticker.png' case 'vue': return 'https://res.cloudinary.com/practicaldev/image/fetch/c_scale,fl_progressive,q_auto,w_180/f_auto/https://thepracticaldev.s3.amazonaws.com/uploads/badge/badge_image/27/vue-sticker.png' case 'css': return 'https://res.cloudinary.com/practicaldev/image/fetch/c_scale,fl_progressive,q_auto,w_180/f_auto/https://thepracticaldev.s3.amazonaws.com/uploads/badge/badge_image/18/57795357-be29b880-7713-11e9-9748-b08c782b58d7.png' case 'angular': return 'https://res.cloudinary.com/practicaldev/image/fetch/c_scale,fl_progressive,q_auto,w_180/f_auto/https://thepracticaldev.s3.amazonaws.com/uploads/badge/badge_image/28/angular-sticker.png' case 'nest': return 'https://docs.nestjs.com/assets/logo-small.svg' case 'life': return 'https://res.cloudinary.com/practicaldev/image/fetch/c_scale,fl_progressive,q_auto,w_180/f_auto/https://thepracticaldev.s3.amazonaws.com/uploads/badge/badge_image/29/graphql-sticker.png' default: return 'https://res.cloudinary.com/practicaldev/image/fetch/c_scale,fl_progressive,q_auto,w_180/f_auto/https://thepracticaldev.s3.amazonaws.com/uploads/badge/badge_image/23/node-sticker.png' } }

稍微设置了一下样式,效果如下:

总结

其实也没啥好总结的,有大家能借鉴的就去用,觉得我的逻辑有问题也尽管提,下一步就去构建后台管理界面,还没想好用什么技术栈,因为前台用了next.js,后台是不是使用react我都没确定。。。

有点缺憾的是后台如果用原生(RN)或者小程序(Taro)的话,总觉得有点怪怪的,不出意外的话,应该是使用 create-react-app或者vue-element-admin来构建。

最新回复(0)