基于后台接口的图书管理案例-(二)-全文详解版
在前端mydemo文件夹中
第一步:在APP.js同层级的component下新建03-grid.js
第二步:在App.js中进行导入
App.js
import React from 'react';
import './App.css';
import TestBox from './component/03-grid.js'
function App () {
return (
<div>
<TestBox/>
</div>
)
}
export default App;
03-grid.js文件如下
/*
图书管理案例
*/
import React from 'react'
import './03-grid.css'
import axios from 'axios'
// 配置axios的基准请求路径
axios.defaults.baseURL = 'http://localhost:3001/'
// axios的响应拦截器
axios.interceptors.response.use((res) => {
// res是axios包装之后的数据
console.log(res)
return res.data
})
class BookManager extends React.Component {
constructor (props) {
super(props)
this.state = {
list: [],
bookId: '',
bookName: '',
// 标志位:控制当前是在添加图书还是在编辑图书(true表示添加;false表示编辑)
flag: true
}
}
loadData = async () => {
// axios.get('books')
// .then(res => {
// // 更新状态数据
// this.setState({
// list: res.data
// })
// })
let res = await axios.get('books')
this.setState({
list: res
})
}
componentDidMount () {
// 初始化数据(调用后台接口获取列表数据)
this.loadData()
// setTimeout(() => {
// // 假设list是后台返回的异步数据
// let list = [{
// id: 1,
// bname: '智能时代'
// }, {
// id: 2,
// bname: '肖申克的救赎'
// }, {
// id: 3,
// bname: '阿甘正传'
// }, {
// id: 4,
// bname: '浪潮之巅'
// }]
// this.setState({
// list: list
// })
// }, 1000)
}
handleId = (e) => {
this.setState({
bookId: e.target.value
})
}
handleBname = (e) => {
this.setState({
bookName: e.target.value
})
}
handleItem = (e) => {
this.setState({
// ES6新特性:对象的属性名称可以是动态的
[e.target.id]: e.target.value
})
}
addBook = async () => {
/*
添加图书:
1、获取表单数据
2、调用后台接口进行添加
3、重新刷新最新类别
4、清空表单
*/
// 表单验证:1、非空验证;2、重复性验证
if (!this.state.bookName) {
// 提示输入,终止后续代码执行-非空验证
alert('请输入图书名称')
return
}
// 非空验证 数组方法some(判断数组中是否有符合条件的数据,主要有一个符合就返回true)
let existFlag = await axios.get('books/book/' + this.state.bookName)
if (existFlag.status === 1) {
// 名称重复,终止后续代码,并给一个提示
alert('图书名称重复了')
return
}
let res = await axios.post('books', {
name: this.state.bookName
})
if (res.status === 200) {
// 添加成功,刷新列表
this.loadData()
this.setState({
// 清空图书表单
bookName: ''
})
}
}
editBook = async () => {
/*
编辑图书
1、获取表单最新数据
2、调用接口提交数据
3、刷新列表并清空表单
*/
let res = await axios.put('books/' + this.state.bookId, {
name: this.state.bookName
})
if (res.status === 200) {
// 编辑成功,刷新列表,清空表单
this.loadData()
this.setState({
bookId: '',
bookName: '',
flag: true
})
}
}
handleSubmit = () => {
// console.log(this.state.bookId)
// console.log(this.state.bookName)
if (this.state.flag) {
// 添加图书
this.addBook()
} else {
// 编辑图书
this.editBook()
}
}
toEdit = async (id) => {
/*
编辑的第一步
1、获取要编辑的图书id
2、根据id调用接口获取编辑的图书信息
3、填充表单
*/
let res = await axios.get('books/' + id)
this.setState({
bookId: res.id,
bookName: res.name,
flag: false
})
}
handleDelete = async (id) => {
/*
删除图书
1、获取要删除的图书ID
2、调用接口删除图书
3、刷新列表
*/
let res = await axios.delete('books/' + id)
if (res.status === 200) {
// 删除成功,刷新列表
this.loadData()
}
}
render () {
// 动态生成表格的列表
let listTag = this.state.list.map(item => {
return (
<tr key={item.id}>
<td>{item.id}</td>
<td>{item.name}</td>
<td>
<a href="#" onClick={this.toEdit.bind(this, item.id)}>编辑</a>
<span>|</span>
<a href="#" onClick={this.handleDelete.bind(this, item.id)}>删除</a>
</td>
</tr>
)
})
return (
<div className='book'>
<div className="title">图书管理系统</div>
<div className="form">
{/*<label htmlFor="bookId">图书编号</label>
<input readOnly={!this.state.flag} value={this.state.bookId} onChange={this.handleItem} type="text" id='bookId'/>*/}
<label htmlFor="bookName">图书名称</label>
<input value={this.state.bookName} onChange={this.handleItem} type="text" id='bookName'/>
<button onClick={this.handleSubmit}>提交</button>
</div>
<div className="grid">
<table>
<thead>
<tr>
<th>图书编号</th>
<th>图书名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{this.state.list.length===0 && <tr>
<td colSpan='3'>正在加载...</td>
</tr>}
{listTag}
</tbody>
</table>
</div>
</div>
)
}
}
export default BookManager
03-grid.css文件如下
.book .title {
text-align: center;
background-color: lightblue;
color: #fff;
font-size: 30px;
}
.book .form {
padding: 10px 0;
}
.book .grid table {
border-collapse: collapse;
width: 100%;
text-align: center;
}
.book .grid table th, td {
border: 1px solid blue;
}
node index.js启动服务器后;npm run start启动项目,(静态或接口数据)页面如下:
在服务器mybook文件夹中
node index.js
启动服务器
第一步:在mybook文件中,cmd启动命令行窗口,npm i axios
安装包,并在03-grid.js中进行引入
import axios from ‘axios’
必要基础配置简述
// 配置axios的基准请求路径
axios.defaults.baseURL = 'http://localhost:3001/'
// axios的响应拦截器
axios.interceptors.response.use((res) => {
// res是axios包装之后的数据
console.log(res)
return res.data
})
在data.json中定义接口数据
[
{
"name": "三国演义",
"date": 2525609975000,
"id": 5
},
{
"name": "水浒传",
"date": 2525609975000,
"id": 6
},
{
"name": "浪潮之巅",
"date": 2525609975000,
"id": "11"
},
{
"name": "JavaScript",
"date": 2525609975000,
"id": 12
},
{
"name": "编辑成功",
"date": 2525609975000,
"id": "13"
},
{
"name": "234",
"date": 2525609975000,
"id": 14
}
]
index.js
const express = require('express');
const path = require('path');
const router = require('./router.js');
const bodyParser = require('body-parser');
const app = express();
// 处理请求参数
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// 设置允许跨域访问该服务, cors
app.all('*', function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, mytoken');
next();
});
// 启动静态资源服务
app.use(express.static('public'));
// app.post('hello', (req,res) => {
// let p = req.body;
// res.end('hello');
// })
// 配置路由
app.use(router);
// 监听端口
app.listen(3001, ()=>{
console.log('running...');
});
router.js
/*
路由模块
*/
const express = require('express');
const router = express.Router();
const service = require('./service.js');
// 查询图书列表
router.get('/books',service.getAllBooks);
// 添加图书(提交表单)
router.post('/books',service.addBook);
// 跳转到编辑图书信息页面
router.get('/books/:id',service.toEditBook);
// router.get('/toEditBook',service.toEditBook);
// 编辑图书提交表单
router.put('/books/:id',service.editBook);
// 删除图书信息
router.delete('/books/:id',service.deleteBook);
// 验证图书名称是否存在
router.get('/books/book/:name',service.checkName);
module.exports = router;
service.js
const data = require('./data.json');
const path = require('path');
const fs = require('fs');
// 自动生成图书编号(自增)
let maxBookCode = ()=>{
let arr = [];
data.forEach((item)=>{
arr.push(item.id);
});
if(arr.length === 0) {
return 0;
} else {
return Math.max.apply(null,arr);
}
}
// 把内存数据写入文件
let writeDataToFile = (res) => {
fs.writeFile(path.join(__dirname,'data.json'),JSON.stringify(data,null,4),(err)=>{
if(err){
res.json({
status: 500
});
}
res.json({
status: 200
});
});
}
// 验证图书名称是否存在
exports.checkName = (req,res) => {
let name = req.params.name;
console.log(req.params)
let flag = false;
data.some(item=>{
if(name == item.name) {
flag = true;
return true;
}
})
if(flag) {
res.json({
status: 1
})
}else{
res.json({
status: 2
})
}
}
// 获取图书列表数据
exports.getAllBooks = (req,res) => {
res.json(data);
}
// 添加图书保存数据
exports.addBook = (req,res) => {
// 获取表单数据
let info = req.body;
let book = {};
for(let key in info){
book[key] = info[key];
}
book.date = 2525609975000;
book.id = maxBookCode() + 1;
data.push(book);
// 把内存中的数据写入文件
writeDataToFile(res);
}
// 跳转编辑图书页面
exports.toEditBook = (req,res) => {
let id = req.params.id;
let book = {};
data.some((item)=>{
if(id == item.id){
book = item;
return true;
}
});
res.json(book);
}
// 编辑图书更新数据
exports.editBook = (req,res) => {
let info = req.body;
info.id = req.params.id;
data.some((item)=>{
if(info.id == item.id){
for(let key in info){
item[key] = info[key];
}
return true;
}
});
// 把内存中的数据写入文件
writeDataToFile(res);
}
// 删除图书信息
exports.deleteBook = (req,res) => {
let id = req.params.id;
data.some((item,index)=>{
if(id == item.id){
// 删除数组的一项数据
data.splice(index,1);
return true;
}
});
// 把内存中的数据写入文件
writeDataToFile(res);
}
css/index.css
.grid {
margin: auto;
width: 530px;
text-align: center;
}
.grid table {
border-top: 1px solid #C2D89A;
width: 100%;
border-collapse: collapse;
}
.grid th,td {
padding: 10;
border: 1px dashed #F3DCAB;
height: 35px;
line-height: 35px;
}
.grid th {
background-color: #F3DCAB;
}
.grid .book {
padding-bottom: 10px;
padding-top: 5px;
background-color: #F3DCAB;
}
.grid .total {
height: 30px;
line-height: 30px;
background-color: #F3DCAB;
border-top: 1px solid #C2D89A;
}
s/index.css
.grid {
margin: auto;
width: 530px;
text-align: center;
}
.grid table {
border-top: 1px solid #C2D89A;
width: 100%;
border-collapse: collapse;
}
.grid th,td {
padding: 10;
border: 1px dashed #F3DCAB;
height: 35px;
line-height: 35px;
}
.grid th {
background-color: #F3DCAB;
}
.grid .book {
padding-bottom: 10px;
padding-top: 5px;
background-color: #F3DCAB;
}
.grid .total {
height: 30px;
line-height: 30px;
background-color: #F3DCAB;
border-top: 1px solid #C2D89A;
}