随着互联网的不断发展,网站搭建和后台管理成为了必不可少的部分。在这个多元化的互联网时代,每个网站都需要一个高效的管理系统。而CMS系统(内容管理系统)则成为最流行的解决方案之一。因此,我们在这篇文章中将介绍如何使用Node.js + Koa2 + React来开发一个全功能的CMS系统。
环境搭建
在开始实战之前,我们需要在本地先搭建开发环境。首先,我们需要安装Node.js和npm。然后,使用以下命令安装Koa2和React依赖:
npm i koa koa-router koa-static koa-bodyparser koa-compress koa-jwt react react-dom react-redux redux redux-logger redux-thunk react-router-dom axios --save
以上是我们需要的基本依赖。在实际的开发过程中,我们可能还需要一些其他的依赖。接下来,我们开始进入实际的开发。
项目结构
在开始项目的搭建之前,我们需要确认好项目的目录结构。如下所示:
// javascriptcn.com 代码示例 ├── client // 前端代码 │ ├── build // 打包后的代码 │ ├── public // 静态资源 │ └── src │ ├── components // 共用组件 │ ├── pages // 页面组件 │ ├── router // 路由配置 │ ├── store // Redux store配置 │ ├── App.js // 入口组件 │ └── index.js // 入口文件 ├── server // 后端代码 │ ├── config // 配置文件 │ ├── middleware // 中间件 │ ├── routers // 路由配置 │ ├── app.js // Koa2 app实例 │ ├── index.js // 入口文件 │ └── service // 数据库操作 ├── README.md └── package.json
我们可以看到,这个项目由client和server两部分组成,其中client是前端代码,server是后端代码。
后端代码
创建Koa2实例
我们先看一下后端代码的入口文件index.js。在这个文件中,我们要做的第一件事情就是创建一个Koa2实例。代码如下:
// javascriptcn.com 代码示例 const Koa = require('koa') const app = new Koa() // 为app实例添加中间件 require('./middleware')(app) // 路由配置 require('./routers')(app) // 启动程序 app.listen(3000, () => { console.log('Server is running at http://localhost:3000') })
中间件
接下来,我们需要添加中间件。在本项目中,我们需要添加的中间件有koa-bodyparser、koa-compress、koa-jwt、koa-router和koa-static。其中,koa-jwt用来验证用户登录状态。代码如下:
// javascriptcn.com 代码示例 const bodyParser = require('koa-bodyparser') const compress = require('koa-compress') const jwt = require('koa-jwt') const router = require('koa-router')() const serve = require('koa-static') module.exports = app => { // 请求体解析器 app.use(bodyParser()) // 静态资源 app.use(serve('./public')) // 压缩 app.use(compress()) // 验证token app.use(jwt({ secret: 'your secret' }).unless({ path: [/^\/api\/login/, /^\/public/] })) // 路由 app.use(router.routes()).use(router.allowedMethods()) }
路由
我们已经添加了中间件,接下来就是路由的配置。我们在项目中创建了一个routers文件夹,用来存放所有的路由。代码如下:
module.exports = app => { require('./user')(app) // ... }
脚手架代码如下:
// javascriptcn.com 代码示例 const Router = require('koa-router') const router = new Router() router.post('/create', async ctx => { // 创建文章 }) router.post('/delete', async ctx => { // 删除文章 }) router.post('/update', async ctx => { // 更新文章 }) router.get('/list', async ctx => { // 获取文章列表 }) module.exports = router
数据库操作
最后一个重要的部分就是数据库操作。我们在项目中创建了一个service文件夹,用来存放所有的数据库操作。这个项目我们使用了Mongoose来连接MongoDB数据库。代码如下:
// javascriptcn.com 代码示例 const mongoose = require('mongoose') mongoose.set('useFindAndModify', false) mongoose.set('useCreateIndex', true) // 连接数据库 mongoose.connect('mongodb://localhost:27017/cms', { useNewUrlParser: true }) const db = mongoose.connection db.on('error', console.error.bind(console, 'connection error:')) db.once('open', function () { console.log('MongoDB is connected!') }) const userSchema = mongoose.Schema({ username: String, password: String, }) const User = mongoose.model('User', userSchema) module.exports = { User, }
前端代码
创建React组件
首先,我们要创建一个React组件作为全局入口文件。在这个文件中,我们需要渲染根组件。代码如下:
// javascriptcn.com 代码示例 import React from 'react' import ReactDom from 'react-dom' import { Provider } from 'react-redux' import store from './store' import Router from './router' ReactDom.render( <Provider store={store}> <Router /> </Provider>, document.getElementById('root') )
接下来,我们开始创建Router组件。代码如下:
// javascriptcn.com 代码示例 import React from 'react' import { BrowserRouter, Switch, Route, Redirect } from 'react-router-dom' import Login from './pages/login' import Layout from './pages/layout' const Router = () => { return ( <BrowserRouter> <Switch> <Route path="/login" exact component={Login} /> <Route path="/" component={Layout} /> <Redirect to="/" /> </Switch> </BrowserRouter> ) } export default Router
Redux配置
好了,我们已经创建了Router组件,接下来我们需要配置Redux。我们在项目中创建了一个store文件夹,用来存放store文件。代码如下:
// javascriptcn.com 代码示例 import { createStore, applyMiddleware } from 'redux' import thunk from 'redux-thunk' import logger from 'redux-logger' import rootReducer from './reducers' const middleware = [thunk] // 仅在开发环境中添加logger,生产环境不添加 if (process.env.NODE_ENV === 'development') { middleware.push(logger) } const store = createStore( rootReducer, applyMiddleware(...middleware) ) export default store
这个store导出了一个完全配置好了的store实例,而我们的reducers文件则会在下一步创建。
页面组件
再往下,我们需要开始自己定义页面组件。在这个项目中,我们只创建了两个页面,一个用于用户登录,另一个则是整个CMS系统的布局。代码如下:
Login组件
// javascriptcn.com 代码示例 import React, { useState } from 'react' import { useDispatch } from 'react-redux' import { Redirect } from 'react-router-dom' import { loginAction } from '../../store/actions/user' const Login = () => { const [username, setUsername] = useState('') const [password, setPassword] = useState('') const [redirectTo, setRedirectTo] = useState(null) const dispatch = useDispatch() const handleLogin = async () => { try { await dispatch(loginAction(username, password)) setRedirectTo('/') } catch (e) { console.log(e) } } if (redirectTo) { return <Redirect to={redirectTo} /> } return ( <div> <input type="text" value={username} onChange={e => setUsername(e.target.value)} /> <input type="password" value={password} onChange={e => setPassword(e.target.value)} /> <button onClick={handleLogin}>登录</button> </div> ) } export default Login
Layout组件
// javascriptcn.com 代码示例 import React from 'react' const Layout = () => { return ( <div> <div>头部</div> <div> <div>侧边栏</div> <div>内容区</div> </div> </div> ) } export default Layout
Redux、API、样式
现在我们需要开始写Redux、API、样式了。代码如下:
// javascriptcn.com 代码示例 // Redux import { combineReducers } from 'redux' import { userReducer } from './user' const rootReducer = combineReducers({ user: userReducer, }) export default rootReducer
// javascriptcn.com 代码示例 // actions/user.js import axios from 'axios' import { LOGIN_SUCCESS } from '../constants/user' export const loginAction = (username, password) => async (dispatch) => { const res = await axios.post('/api/login', { username, password }) if (res.data.success) { dispatch({ type: LOGIN_SUCCESS, payload: res.data.token, }) } else { throw new Error('登录失败') } } // constants/user.js export const LOGIN_SUCCESS = 'LOGIN_SUCCESS' // reducers/user.js import { LOGIN_SUCCESS } from '../constants/user' const initialState = { token: localStorage.getItem('token') || '' } export const userReducer = (state = initialState, action) => { switch (action.type) { case LOGIN_SUCCESS: localStorage.setItem('token', action.payload) return { ...state, token: action.payload, } default: return state } }
// javascriptcn.com 代码示例 // API.js import axios from 'axios' axios.defaults.baseURL = process.env.NODE_ENV === 'development' ? 'http://localhost:3000' : '' export default axios // usage: import API from './API' API.get('/api/posts').then(res => { console.log(res) })
/* public/style.css */ body { margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; }
请求
接下来我们开始编写API请求。
// javascriptcn.com 代码示例 // 服务端/login router.post('/login', async ctx => { const user = await User.findOne({ username: ctx.request.body.username }) if (user && user.password === ctx.request.body.password) { const token = jwt.sign({ username: user.username }, 'your secret') ctx.body = { success: true, token, } } else { ctx.body = { success: false, message: '用户名或密码错误', } } }) // 前端登录请求 import API from '../API' export const loginAction = (username, password) => async (dispatch) => { const res = await API.post('/login', { username, password }) if (res.data.success) { dispatch({ type: LOGIN_SUCCESS, payload: res.data.token, }) } else { throw new Error(res.data.message) } }
启动项目
最后,我们需要在命令行启动项目。需要先cd到server和client目录下,使用以下命令即可:
cd server nodemon index.js cd ../client npm start
启动完成后,我们可以在浏览器中访问http://localhost:3000,看到我们创建的系统界面。
总结
基于Node.js + Koa2 + React的CMS系统开发过程中,我们初步介绍了整个项目的结构和部分代码实现。在实际开发中,仅仅是简单地介绍原理和代码使用远远不够,我们还需要自己去逐渐熟悉Connect、Koa2、React以及Redux等框架。本文仅仅是作为一个入门教程为大家提供一些引导。在之后的实际开发中,我们会逐渐深入探讨Node.js + Koa2 + React的各种实战应用,为大家提供更多帮助和指导。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/652e68bc7d4982a6ebf6f1ca