P19:前台文章列表页-接口模块化和读取文章分类
从本文开始,要制作一下文章列表页的前中台结合。由于接口越来越多,现在这样零散的管理非常不利于日后的维护,所以需要单独一个文件,专门用于前台和中台的接口管理。这样在以后部署和更换服务器时都非常简单。
编写统一中台 API 配置文件
在blog
的根目录下,新建一个config
文件夹,然后在文件夹下建立一个apiUrl.js
文件,写入下面的代码。
let ipUrl = 'http://127.0.0.1:7001/default/' let servicePath = { getArticleList:ipUrl + 'getArticleList' , // 首页文章列表接口 getArticleById:ipUrl + 'getArticleById/', // 文章详细页内容接口 ,需要接收参数 } export default servicePath;
完成后,可以去pages/index.js
文件中,修改以前的接口路由,在修改前,需要先进行引入。
import servicePath from '../config/apiUrl'
引入后,找到getInitialProps
方法直接进行更换
Home.getInitialProps = async () => { const promise = new Promise((resolve) => { axios(servicePath.getArticleList).then( (res) => { resolve(res.data) } ) }) return await promise }
首页更换完成,再去pages/detailed.js
(详细页)文件中进行更换。
//记得要先进行引入 import servicePath from '../config/apiUrl' //引入后进行修改 Detailed.getInitialProps = async(context)=>{ let id =context.query.id const promise = new Promise((resolve)=>{ axios(servicePath.getArticleById+id).then( (res)=>{ resolve(res.data.data[0]) } ) }) return await promise }
这样我们就形成了一个统一的接口管理文件,以后在维护上会方便很多。
修改首页接口 读取文章类别信息
我们希望每个页面只读取一次接口,然后服务端渲染好后展示给我们,这时候就需要在首页的getArticleList
接口中进行修改了。
文件位置/service/app/default/home.js
修改的代码如下:
// 得到类别名称和编号 async getTypeInfo() { const result = await this.app.mysql.select('type'); this.ctx.body = { data: result }; }
接口写好之后,就需要我们到服务端配置路由service/app/router/default.js
'use strict'; module.exports = app => { const { router, controller } = app; router.get('/default/index', controller.default.home.index); router.get('/default/getArticleList', controller.default.home.getArticleList); router.get('/default/getArticleById/:id', controller.default.home.getArticleById); router.get('/default/getTypeInfo', controller.default.home.getTypeInfo); };
修改数据库
因为我们设计的是有 Icon 的,但是这个数据缺少一个图标选项,现在把图标也存入数据库中。关于图标这一块我使用的是 iconfont 自定义图标,官方文档
我们打开 mysql 的管理,然后在里边加入icon
字段。
- 前端教程 字段为
iconclass-9
- 前端工具 字段为
icontoolset
- 随笔 字段为
iconnote
这时候我们就有了图标字段并且有了值,再次修改<Header>
组件的代码,加入图标的部分,并且把博客首页也加上去。
修改 Header 组件
以前我们的 Header 组件是静态写死的,现在我们需要利用useEffect()
方法来从接口中获取动态数据。
需要先引入useState
和useEffect
,然后由于还要进行跳转,所以还要引入Router
和Link
,由于还要访问接口,所以还要引入axios
和servicePath
。
import React ,{useState,useEffect} from 'react' import Router from 'next/router' import Link from 'next/link' import axios from 'axios' import servicePath from '../config/apiUrl'
引入后用useState
声明navArray
和使用useEffect()
获取远程数据
useEffect(()=>{ const fetchDate = async () => { const result = await axios(servicePath.getTypeInfo).then( (res) => { return res.data.data } ) setNavArray(result); } fetchDate() },[]);
useEffect()
写完后,可以获得博客的分类信息了,要想让分类信息可以跳转,可以写一个方法handleClick
。
//跳转到列表页 const handleClick = (e) => { if (e.key == 0) { Router.push('/index'); } else { Router.push('/list?id='+e.key) } }
这些都准备好以后,就可以写我们的 JSX 语法,修改<Menu>
组件部分了,代码如下:
<Col className="memu-div" xs={0} sm={0} md={14} lg={8} xl={6}> <Menu mode="horizontal" onClick={handleClick}> <Menu.Item key="0"> <IconFont type="iconhome" /> 首页 </Menu.Item> { navArray.map((item)=>{ return ( <Menu.Item key={item.Id}> <IconFont type={item.icon} /> {item.typeName} </Menu.Item> ) }) } </Menu> </Col>
最后为了方便大家学习,这里给出全部的Header.js
代码。
import React ,{useState,useEffect} from 'react' import Router from 'next/router' import Link from 'next/link' import axios from 'axios' import servicePath from '../config/apiUrl' import {Row, Col, Menu} from 'antd' import {createFromIconfontCN} from '@ant-design/icons' const Header = () => { const [navArray, setNavArray] = useState([]); useEffect(()=>{ const fetchDate = async () => { const result = await axios(servicePath.getTypeInfo).then( (res) => { return res.data.data } ) setNavArray(result); } fetchDate() },[]); const handleClick = (e) => { if (e.key == 0) { Router.push('/index'); } else { Router.push('/list?id='+e.key) } } const IconFont = createFromIconfontCN({ scriptUrl: '//at.alicdn.com/t/font_2253148_geubuprv3qb.js', }); return ( <div className="header"> <Row type="flex" justify="center"> <Col xs={24} sm={24} md={10} lg={15} xl={12}> <span className="header-logo"> <Link href={{pathname:'/index'}}> <a> 码云笔记</a> </Link> </span> <span className="header-txt">专注前端开发,实战技巧分享。</span> </Col> <Col className="memu-div" xs={0} sm={0} md={14} lg={8} xl={6}> <Menu mode="horizontal" onClick={handleClick}> <Menu.Item key="0"> <IconFont type="iconhome" /> 首页 </Menu.Item> { navArray.map((item)=>{ return ( <Menu.Item key={item.Id}> <IconFont type={item.icon} /> {item.typeName} </Menu.Item> ) }) } </Menu> </Col> </Row> </div> ) } export default Header
打开浏览器看一下效果:
码云笔记 » P19:前台文章列表页-接口模块化和读取文章分类