✨该模块搭建承接上一个笔录:Vue3+Node.js
前端:vue3+element-plus+axios+vite


../utils/http.js
javascript
// axios 二次封装
// 1、导入核心库
import axios from "axios";
// 2、配置路径
axios.defaults.baseURL = 'http://localhost:3000'
// axios.defaults.withCredentials = true
// 3、请求拦截器
axios.interceptors.request.use(config =>config);
// 4、响应拦截器
axios.interceptors.response.use(
res =>{
if(res.status == 200){
return res.data
}
return res;
},
error=>Promise.reject(error)
);
// 5、导出
export default axios;
home.vue
html
<script setup>
import { onMounted,reactive,ref} from 'vue'
import {useRouter} from 'vue-router'
import axios from "../utils/http.js"
import HelloWorld from '../components/HelloWorld.vue'
const router = useRouter()
const ruleFormRef = ref()
const ruleForm = reactive({
product_name: '',
product_price: '',
})
const tableData2 = ref([]);
const edit_id = ref('')
function goPage(){
router.push('/about?name=Jen');
}
onMounted(() => {
// 首次获取数据,渲染列表
onGetData()
})
/**
* 获取数据,渲染列表
*/
const onGetData = async() => {
try {
const {code,list} = await axios.get('/api/getInfo');
if(code == 200){
// 0 从数组的第 0 个元素开始操作。
// tableData.length 清空数组中所有的旧数据。
// ...list 把新数据填进去。
// tableData.splice(0, tableData.length, ...list)
// 替换方案 建议用tableData.value = list 形式,能直接赋值
tableData2.value = list
}
} catch (error) {
console.error('获取数据失败:', error);
}
}
/**
* 数值规则
*/
const checkNum = (rule, value, callback) => {
if (value === '') return callback(new Error('Please input the price'))
if (value <= 0) callback(new Error('Price must be greater than 0'))
setTimeout(() => {
if (isNaN(value)) {
callback(new Error('Please input digits'))
} else {
callback()
}
}, 500)
}
/**
* 表单规则
*/
const rules = reactive({
product_name: [
{ required: true, message: 'Please input product name', trigger: 'blur' },
{ min: 1, max: 10, message: 'Length should be 1 to 10', trigger: 'blur' },
],
product_price: [{ required: true,validator: checkNum, trigger: 'blur' }],
})
/**
* 提交表单
* 添加/删除操作
*/
const submitForm = (formEl) => {
if (!formEl) return
formEl.validate(async (valid) => {
if (valid) {
// 保留两位小数 浮点数四舍五入 位数不够 不补0
ruleForm.product_price = Math.round(ruleForm.product_price * Math.pow(10, 2))/Math.pow(10, 2);
try {
let res_code = 0;
if(edit_id.value){
const {code} = await axios.post('/api/editInfo',{id:edit_id.value,...ruleForm});
res_code = code
}else{
const {code} = await axios.post('/api/addInfo',ruleForm);
res_code = code
}
if(res_code == 200){
resetForm(ruleFormRef.value)
onGetData()
}
} catch (error) {
console.error('提交数据失败:', error);
}
} else {
console.log('error submit!')
}
})
}
/**
* 重置表单
*/
const resetForm = (formEl) => {
if (!formEl) return
formEl.resetFields()
edit_id.value = ""
}
/**
* 修改功能
* 编辑表单某条数据
*/
function editFun(row){
edit_id.value = row.id
Object.assign(ruleForm, {product_name:row.product_name,product_price:row.product_price})
}
/**
* 删除功能
* 删除表单某条数据
*/
async function delFun(id){
const {code} = await axios.post('/api/delInfo',{id});
if(code == 200) onGetData()
}
</script>
<template>
<div>
<el-form
ref="ruleFormRef"
style="max-width: 600px"
:model="ruleForm"
status-icon
:rules="rules"
label-width="auto"
class="demo-ruleForm"
>
<el-form-item label="商品名称" prop="product_name">
<el-input v-model="ruleForm.product_name" />
</el-form-item>
<el-form-item label="商品价格" prop="product_price">
<el-input v-model.number="ruleForm.product_price" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm(ruleFormRef)">
{{edit_id?'修改':'添加'}}
</el-button>
<el-button @click="resetForm(ruleFormRef)">重置</el-button>
</el-form-item>
</el-form>
<div>
<el-table :data="tableData2" border style="width: 100%">
<el-table-column prop="id" label="id" />
<el-table-column prop="product_name" label="商品名称" />
<el-table-column prop="product_price" label="商品价格" />
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
<el-button type="primary" @click.prevent="editFun(scope.row)">修改</el-button>
<el-button type="danger" @click.prevent="delFun(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
后端:koa+@koa/router+mysql2

package.json(CommonJS)
javascript
{
"name": "nodeserve",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"dev": "nodemon server.js",
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"dependencies": {
"@koa/router": "^15.4.0",
"koa": "^3.2.0",
"koa-bodyparser": "^4.4.1",
"koa-static": "^5.0.0",
"koa2-cors": "^2.0.6",
"mysql2": "^3.22.2"
}
}
server.js (CommonJS)
javascript
// koa ------ 基于Node.js平台的下一代web开发框架
// 运用node.js中的koa框架创建一个http服务器
// "type": "commonjs",
//引入koa模块
const Koa = require('koa');
// 引入路由库
const Router = require('@koa/router');
// 引入处理跨域组件
const cors = require('koa2-cors');
// 引入处理请求体解析
const BodyParser = require('koa-bodyparser');
// 使用promise版本
const mysql = require('mysql2/promise');
// 实例化
const app = new Koa(); //创建应用程序实例
const router = new Router({prefix:'/api'}); //实例化一个Router对象,并设置一个路由访问前缀
const bodyparser = new BodyParser();
// koa请求跨域配置(注意:一定要在路由使用前设置)
app.use(
cors({
origin:function(ctx){ //指定允许跨域访问的源。
// return ctx.request.headers.origin || ""; //动态获取地址 //当 credentials: true 时,不能设置为 *,必须是具体的域名。
// 白名单
const whiteList = ['http://localhost:5173', 'https://www.yourdomain.com'];
const requestOrigin = ctx.request.header.origin;
// 如果请求源在白名单内,则返回该请求源;否则不允许跨域
if (whiteList.includes(requestOrigin)) {
return requestOrigin;
}
return false;
// 如果想允许所有域名并且携带cookie,可以直接返回请求源(不安全,仅用于开发环境)
// return requestOrigin || '*';
},
credentials:true,
// exposeHeaders:["WWW-Authenticate","Server-Authorization"],
allowMethods:["GET","POST","PUT","DELETE","OPTIONS"],
allowHeaders:["Content-Type","Authorization","Accept"]
})
)
app.use(bodyparser);
// 加载路由
app.use(router.routes()).use(router.allowedMethods());
// 创建数据库连接池
const pool = mysql.createPool({
host:'localhost',
user:'item01DB',
password:'item01DB',
database:'item01DB' //要连接的数据库名
})
// 测试连接
pool.getConnection()
.then(conn => {
console.log('数据库连接成功');
conn.release(); //释放连接
})
.catch(err => {
console.log('数据库连接失败',err);
})
// 查询接口
router.get('/getInfo',async (ctx)=> {
// 数据库查询数据
const [rows] = await pool.execute('select * from product');
ctx.body = {
code:200,
message:'success',
list:rows
}
})
// 添加接口
router.post('/addInfo',async (ctx) => {
// 接受前端传的参数
let {product_name,product_price} = ctx.request.body;
// 操作数据库
await pool.execute(
'insert into product (product_name,product_price) values (?,?)',
[product_name,product_price]
)
ctx.body = {
code:200,
message:'success'
}
})
// 修改接口
router.post('/editInfo',async (ctx) => {
// 接受前端传的参数
let {product_name,product_price,id} = ctx.request.body;
// 操作数据库
await pool.execute(
'update product set product_name = ?,product_price = ? where id = ?',
[product_name,product_price,id]
)
ctx.body = {
code:200,
message:'success'
}
})
// 删除接口
router.post('/delInfo',async (ctx) => {
// 接受前端传的参数
let {id} = ctx.request.body;
// 操作数据库
await pool.execute(
'delete from product where id = ?',
[id]
)
ctx.body = {
code:200,
message:'success'
}
})
//启动成功,访问端口号3000
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});
package.json(ES Module)
javascript
{
"name": "nodeserve",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"dev": "nodemon server.js",
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "module",
"dependencies": {
"@koa/router": "^15.4.0",
"koa": "^3.2.0",
"koa-bodyparser": "^4.4.1",
"koa-static": "^5.0.0",
"koa2-cors": "^2.0.6",
"mysql2": "^3.22.2"
}
}
server.js (ES Module)
javascript
// // koa ------ 基于Node.js平台的下一代web开发框架
// // 运用node.js中的koa框架创建一个http服务器
// // "type": "module",
// //引入koa模块
// import Koa from 'koa';
// const app = new Koa(); //创建应用程序实例
// // 引入路由库
// import Router from "@koa/router";
// const router = new Router(); //实例化一个Router对象
// // 设置默认端口号和主机名
// const hostname = '127.0.0.1';
// const port = 1823;
// // ------GET 请求
// router.get('/',async ctx => {
// ctx.body = "测试get请求";
// })
// // ------GET 请求 http://localhost:1823/test?id=001&web=testapi
// router.get('/test',async ctx => {
// let id = ctx.query.id;
// let web = ctx.query.web;
// ctx.body = id + ":" + web;
// })
// app.listen(port,hostname,()=>{
// console.log(`服务器已启动:http://${hostname}:${port}`);
// })
// // 添加中间件
// app.use(async ctx => {
// ctx.body = "Hello World3";
// });
// //启动成功,访问端口号3000
// // app.listen(3000, () => {
// // console.log('Server is running on http://localhost:3000');
// // });