4:用实战提升你的---Vue前后端交互(2)
Vue前后端交互案例(图书管理)前言:本案例在:2:Vue常用特性中静态实现过,本次实战,我们用axios请求动态数据的方式来实现(奥利给)1.首先:node服务器先奉上(涵盖本文所有路由)app.js(入口文件,启动服务器)const express = require('express');const path = require('path');const router = require(
·
Vue前后端交互案例(图书管理)
前言:本案例在:2:Vue常用特性中静态实现过,本次实战,我们用axios请求动态数据的方式来实现(奥利给)
1.首先:node服务器先奉上(涵盖本文所有路由)
- app.js(入口文件,启动服务器)
const express = require('express');
const path = require('path');
const router = require('./router.js');
const bodyParser = require('body-parser');
const app = express();
// 启动静态资源服务
app.use(express.static('public'));
// 处理请求参数
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// 配置路由
app.use(router);
// 监听端口
app.listen(3000, () => {
console.log('running...');
});
- router.js(路由模块,分配请求路径)
// 引入express框架
const express = require('express');
//搭建二级路由
const router = express.Router();
//引入service模块
const service = require('./service');
//展示功能
router.get('/books', service.getAllBooks);
//验证图书是否存在
router.get('/books/book/:name', service.checkName);
//防止书名为空报错
router.get('/books/book/', (req, res) => {
res.json({
status: 3
});
});
//添加图书
router.post('/books', service.addBooks);
// 编辑图书根据id查询图书信息
router.get('/books/:id', service.ToEditBook);
//编辑图书
router.put('/books/:id', service.editBook);
//删除图书
router.delete('/books/:id', service.deleteBook);
//暴露出去
module.exports = router;
- service.js(功能模块,用于实现功能)
// 引入json文件测试
const data = require('./data.json');
//引入路径模块
const path = require('path');
//引入操作文件模块
const fs = require('fs');
// 自动生成图书编号(自增)
let maxBookCode = () => {
let arr = [];
data.forEach((item) => {
arr.push(item.id);
});
// 返回数组中最大数
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.getAllBooks = (req, res) => {
res.send(data);
};
//添加图书
exports.addBooks = (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.checkName = (req, res) => {
let name = req.params.name;
if (name.trim().length == 0) {
res.json({
status: 3
})
}
// console.log(name);
let flag = false;
data.some(item => {
if (item.name == name) {
flag = true;
return true;
}
});
if (flag) {
res.json({
status: 1
});
} else {
res.json({
status: 2
})
}
};
// 编辑图书根据id查找图书
exports.ToEditBook = (req, res) => {
let id = req.params.id;
book = {};
data.some((item) => {
if (id == item.id) {
book = item;
return true;
}
});
res.json(book);
};
// 编辑图书功能
exports.editBook = (req, res) => {
let info = req.body;
let id = req.params.id;
data.some(item => {
if (item.id == 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);
}
此处用json文件data模拟数据库数据
- data.json
[
{
"id": "4",
"name": "红楼梦",
"date": 2525609975000
},
{
"name": "三国演义",
"date": 2525609975000,
"id": 5
},
{
"name": "水浒传",
"date": 2525609975000,
"id": 6
},
{
"name": "西游记",
"date": 2525609975000,
"id": 7
}
]
ok 车先开起来(服务器啦)
2.客户端工作
预览:
分功能逐个完成:
- 基于接口案例-获取图书列表
- 导入axios 用来发送ajax
- 把获取到的数据渲染到页面上
<div id="app">
<div class="grid">
<table>
<thead>
<tr>
<th>编号</th>
<th>名称</th>
<th>时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<!-- 5. 把books 中的数据渲染到页面上 -->
<tr :key='item.id' v-for='item in books'>
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.date }}</td>
<td>
<a href="">修改</a>
<span>|</span>
<a href="">删除</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
1. 导入axios
<script type="text/javascript" src="js/axios.js"></script>
<script type="text/javascript">
/*
图书管理-添加图书
*/
# 2 配置公共的url地址 简化后面的调用方式
axios.defaults.baseURL = 'http://localhost:3000/';
axios.interceptors.response.use(function(res) {
return res.data;
}, function(error) {
console.log(error)
});
var vm = new Vue({
el: '#app',
data: {
flag: false,
submitFlag: false,
id: '',
name: '',
books: []
},
methods: {
# 3 定义一个方法 用来发送 ajax
# 3.1 使用 async 来 让异步的代码 以同步的形式书写
queryData: async function() {
// 调用后台接口获取图书列表数据
// var ret = await axios.get('books');
// this.books = ret.data;
# 3.2 发送ajax请求 把拿到的数据放在books 里面
this.books = await axios.get('books');
}
},
mounted: function() {
# 4 mounted 里面 DOM已经加载完毕 在这里调用函数
this.queryData();
}
});
</script>
- 添加图书
- 获取用户输入的数据 发送到后台
- 渲染最新的数据到页面上
methods: {
handle: async function(){
if(this.flag) {
// 编辑图书
// 就是根据当前的ID去更新数组中对应的数据
this.books.some((item) => {
if(item.id == this.id) {
item.name = this.name;
// 完成更新操作之后,需要终止循环
return true;
}
});
this.flag = false;
}else{
# 1.1 在前面封装好的 handle 方法中 发送ajax请求
# 1.2 使用async 和 await 简化操作 需要在 function 前面添加 async
var ret = await axios.post('books', {
name: this.name
})
# 1.3 根据后台返回的状态码判断是否加载数据
if(ret.status == 200) {
# 1.4 调用 queryData 这个方法 渲染最新的数据
this.queryData();
}
}
// 清空表单
this.id = '';
this.name = '';
},
}
- 验证图书名称是否存在
- 添加图书之前发送请求验证图示是否已经存在
- 如果不存在 往后台里面添加图书名称(图书存在与否只需要修改submitFlag的值即可)
watch: {
name: async function(val) {
// 验证图书名称是否已经存在
// var flag = this.books.some(function(item){
// return item.name == val;
// });
var ret = await axios.get('/books/book/' + val);
if(ret.status == 1) {
// 图书名称存在
this.submitFlag = true;
}else{
// 图书名称不存在
this.submitFlag = false;
}
}
},
- 编辑图书
- 根据当前书的id 查询需要编辑的书籍
- 需要根据状态位判断是添加还是编辑
methods: {
handle: async function(){
if(this.flag) {
#4.3 编辑图书 把用户输入的信息提交到后台
var ret = await axios.put('books/' + this.id, {
name: this.name
});
if(ret.status == 200){
#4.4 完成添加后 重新加载列表数据
this.queryData();
}
this.flag = false;
}else{
// 添加图书
var ret = await axios.post('books', {
name: this.name
})
if(ret.status == 200) {
// 重新加载列表数据
this.queryData();
}
}
// 清空表单
this.id = '';
this.name = '';
},
toEdit: async function(id){
#4.1 flag状态位用于区分编辑和添加操作
this.flag = true;
#4.2 根据id查询出对应的图书信息 页面中可以加载出来最新的信息
# 调用接口发送ajax 请求
var ret = await axios.get('books/' + id);
this.id = ret.id;
this.name = ret.name;
},
- 删除图书
- 把需要删除的id书籍 通过参数的形式传递到后台
deleteBook: async function(id){
// 删除图书
var ret = await axios.delete('books/' + id);
if(ret.status == 200) {
// 重新加载列表数据
this.queryData();
}
}
最后奉上整合后的客户端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
.grid {
margin: auto;
width: 500px;
text-align: center;
}
.grid table {
width: 100%;
border-collapse: collapse;
}
.grid th,
td {
padding: 10;
border: 1px dashed #CC0099;
height: 35px;
line-height: 35px;
}
.grid th,
.box,
.num {
background-color: #CC0099;
}
</style>
</head>
<body>
<div id="app">
<div class="grid">
<table>
<div class="box">
编号
<input type="text" v-model="id" disabled="false"> 名称
<input type=" text " v-model="name " v-focus>
<button @click="handle " :disabled="submitFlag">提交</button>
</div>
<div class="num ">
<span>图书总数量为</span>
<span>{{total}}</span>
</div>
<thead>
<tr>
<th>编号</th>
<th>名称</th>
<th>时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr :key="item.id " v-for="(item,index) in books ">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.date | format('yyyy-MM-dd hh:mm:ss')}}</td>
<td>
<a href=" " @click.prevent="editBook(item.id) ">修改</a>
<span>|</span>
<a href=" " @click.prevent="deleteBook(item.id) ">删除</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<script type="text/javascript " src="js/vue.js "></script>
<script src="./js/axios.js "></script>
<script>
// 添加默认路径
axios.defaults.baseURL = 'http://localhost:3000';
// 添加响应接收拦截器
axios.interceptors.response.use(function(ret) {
return ret.data;
}, function(err) {
console.log(err)
})
</script>
<!-- 去除警告 -->
<script>
Vue.config.productionTip = false
</script>
<script type="text/javascript ">
// 图书管理-图书列表展示功能
// 注意事项:<a href=" " @click.prevent>修改</a>
// 事件绑定时,可以只添加修饰符,而不绑定事件函数
//自定义指令(自动聚焦)
Vue.directive('focus', {
inserted: function(e) {
e.focus();
}
})
//过滤时间过滤器
Vue.filter('format', function(value, arg) {
function dateFormat(date, format) {
if (typeof date === "string") {
var mts = date.match(/(\/Date\((\d+)\)\/)/);
if (mts && mts.length >= 3) {
date = parseInt(mts[2]);
}
}
date = new Date(date);
if (!date || date.toUTCString() == "Invalid Date") {
return "";
}
var map = {
"M": date.getMonth() + 1, //月份
"d": date.getDate(), //日
"h": date.getHours(), //小时
"m": date.getMinutes(), //分
"s": date.getSeconds(), //秒
"q": Math.floor((date.getMonth() + 3) / 3), //季度
"S": date.getMilliseconds() //毫秒
};
format = format.replace(/([yMdhmsqS])+/g, function(all, t) {
var v = map[t];
if (v !== undefined) {
if (all.length > 1) {
v = '0' + v;
v = v.substr(v.length - 2);
}
return v;
} else if (t === 'y') {
return (date.getFullYear() + '').substr(4 - all.length);
}
return all;
});
return format;
}
return dateFormat(value, arg);
})
var vm = new Vue({
el: '#app',
data: {
submitFlag: false,
id: '',
name: '',
books: []
// books: [{
// id: 1,
// name: '三国演义',
// date: 2525609975000
// }, {
// id: 2,
// name: '水浒传',
// date: +new Date()
// }, {
// id: 3,
// name: '红楼梦',
// date: +new Date()
// }, {
// id: 4,
// name: '西游记',
// date: +new Date()
// }]
},
methods: {
handle: async function() {
// 判断是添加还是修改
//修改(true)
if (this.flag) {
var ret = await axios.put('/books/' + this.id, {
name: this.name
});
if (ret.status == 200) {
this.queryData();
}
this.flag = false;
} else {
//添加
var ret = await axios.post('/books', {
name: this.name
});
if (ret.status == 200) {
this.queryData();
}
}
//清空输入域内容
this.id = '';
this.name = '';
},
// 修改功能
editBook: async function(id) {
var ret = await axios.get('/books/' + id)
this.id = ret.id;
this.name = ret.name;
//禁用编号区
this.flag = true;
},
// 删除图书
deleteBook: async function(id) {
var ret = await axios.delete('/books/' + id);
if (ret.status == 200) {
this.queryData();
}
},
// 发送请求拿到图书数据
queryData: async function() {
this.books = await axios.get('/books');
}
},
computed: {
total: function() {
return this.books.length;
}
},
watch: {
name: async function(value) {
// 验证是否存在(some返回布尔值)
var ret = await axios.get('/books/book/' + this.name);
console.log(ret);
if (ret.status == 1) {
this.submitFlag = true;
} else {
this.submitFlag = false;
}
}
},
mounted: function() {
this.queryData();
}
});
</script>
</body>
</html>
更多推荐
已为社区贡献20条内容
所有评论(0)