Vue.js + Node.js + Express + MySQL 案例: 创建 CRUD 应用之前端
后端地址为:https://blog.csdn.net/renxingwu2008/article/details/123672189
1、创建前端工程
npm init vite@latest hr_client(项目名称)
vue(选择vue)
下一步
2、初始化并运行项目(注意:默认端口为:3000,这里要与后端端口有所区分)
cd hr_client
npm install
npm run dev
3、安装Element plus
npm install element-plus --save
- 全局引入
import { createApp } from 'vue'
import App from './App.vue'
// 全局引入Element plus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// 这里添加 .use(ElementPlus)
createApp(App).use(ElementPlus).mount('#app')
4、安装vue-router
npm install vue-router
- 全局引用
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// 全局引用 vue-router
import router from './route'
// 这里添加 .use(router)
createApp(App).use(ElementPlus).use(router).mount('#app')
5、安装axios
npm install axios
6、工程目录src
下创建http-common.js
import axios from 'axios'
export default axios.create({
// 后端端口号调整为:9000
baseURL: 'http://localhost:9000/api',
headers: {
'Content-type': 'application/json'
}
})
7、创建vue文件
- 修改工程目录下的
App.vue
内容,将其定为导航页; - 将工程目录下的
components
目录重命名为:views
; - 同时在其目录下创建
HR
目录; HR
目录下创建Users
目录;Users
目录下创建vue文件:UsersList.vue
和AddUser.vue
文件
8、配置路由
- 工程
src
目录下 创建route
目录,目录中创建index.js
import { createWebHistory, createRouter } from "vue-router";
const routes = [
{
path: "/",
alias: "/users",
name: "users",
component: () => import("../views/HR/Users/UsersList.vue")
},
{
path: '/add',
name: 'add',
component: () => import('../views/HR/Users/AddUser.vue')
}
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;
9、配置服务层
工程src
目录下 创建services
目录,目录中创建UserDataService.js
import http from '../http-common'
class UserDataService {
// 获取全部用户
getAll () {
return http.get('/users')
}
// 根据ID获取指定用户信息
get (id) {
return http.get(`/users/${id}`)
}
// 创建一条用户记录
create (data) {
return http.post('/users', data)
}
// 更新一条用户记录
update (id, data) {
return http.put(`/users/${id}`, data)
}
// 删除指定ID用户记录
delete (id) {
return http.delete(`/users/${id}`)
}
// 删除所有用户记录(业务上估计用不上)
deleteAll () {
return http.delete('/users')
}
// 根据用户中文名称查找用户信息
findByUserCN (userCN) {
return http.get(`/users?userCN=${userCN}`)
}
}
export default new UserDataService()
10、编辑vue文件
- App.vue
<template>
<div>
<div id="nav">
<el-menu
class="el-menu-demo"
background-color="#545c64"
mode="horizontal"
text-color="#fff"
active-text-color="#ffd04b"
>
<el-menu-item index="1">简单案例</el-menu-item>
<el-menu-item index="2"><router-link to="/users">用户列表</router-link></el-menu-item>
<el-menu-item index="3"><router-link to="/add">添加用户</router-link></el-menu-item>
</el-menu>
</div>
<router-view />
</div>
</template>
<style>
a {
text-decoration: none;
}
.router-link-active {
text-decoration: none;
}
</style>
- UserList.vue(注意:修改提交的地方有些问题,抽空修改下)
<template>
<div>
<!-- 用户信息列表区域 -->
<el-table :data="users" scope="scope" style="width: 100%">
<el-table-column prop="id" label="ID" width="50" v-if="false" />
<el-table-column prop="userId" label="用户编号" width="100" />
<el-table-column prop="userCN" label="用户姓名" width="100" />
<el-table-column prop="sex" label="用户性别" width="100" />
<el-table-column prop="mobile" label="电话号码" width="180" />
<el-table-column prop="telNo" label="办公电话" width="180" />
<el-table-column prop="email" label="用户邮箱" width="300" />
<el-table-column prop="roomNO" label="房间号" width="180" />
<el-table-column prop="address" label="家庭地址" />
<el-table-column label="操作" width="200">
<template v-slot="scope">
<el-button type="primary" @click="editUser(scope.row)">修改</el-button>
<el-button type="danger" @click="delUser(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 修改用户信息弹窗区域 -->
<el-dialog v-model="dialogFormVisible" :show-close="false">
<div class="head"></div>
<el-card
class="box-card"
:body-style="{ padding: '20px', width: '80%', margin: '0 auto' }">
<!-- 卡片头部分 -->
<template #header>
<div>
添加用户信息
</div>
</template>
<!-- 表单字段部分 -->
<el-form label-position="right" label-width="100%">
<el-divider content-position="left">基本信息</el-divider>
<el-row>
<el-col :span="4">
<div><el-form-item label="用户编号:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div><el-input v-model="userData.userId" disabled></el-input></div>
</el-col>
<el-col :span="4">
<div><el-form-item label="用户账号:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div><el-input v-model="userData.userName"></el-input></div>
</el-col>
</el-row>
<el-row>
<el-col :span="4">
<div><el-form-item label="中文名称:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div><el-input v-model="userData.userCN"></el-input></div>
</el-col>
<el-col :span="4">
<div><el-form-item label="用户性别:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div>
<el-radio-group v-model="userData.sex">
<el-radio label="男"></el-radio>
<el-radio label="女"></el-radio>
</el-radio-group>
</div>
</el-col>
</el-row>
<el-divider content-position="left">办公信息</el-divider>
<el-row>
<el-col :span="4">
<div><el-form-item label="移动电话:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div><el-input v-model="userData.mobile"></el-input></div>
</el-col>
<el-col :span="4">
<div><el-form-item label="办公电话:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div><el-input v-model="userData.telNo"></el-input></div>
</el-col>
</el-row>
<el-row>
<el-col :span="4">
<div><el-form-item label="电子邮箱:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div><el-input v-model="userData.email"></el-input></div>
</el-col>
<el-col :span="4">
<div><el-form-item label="房间号码:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div><el-input v-model="userData.roomNO"></el-input></div>
</el-col>
</el-row>
<el-row>
<el-col :span="4">
<div><el-form-item label="是否有效:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div>
<el-radio-group v-model="userData.isEffective">
<el-radio label="是"></el-radio>
<el-radio label="否"></el-radio>
</el-radio-group></div>
</el-col>
<el-col :span="4">
<div><el-form-item label="有效期至:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div>
<el-date-picker type="date" v-model="userData.effectTime" placeholder="选择有效截止日期" style="width: 100%"></el-date-picker>
</div>
</el-col>
</el-row>
<el-divider content-position="left">其他信息</el-divider>
<el-row>
<el-col :span="4">
<div><el-form-item label="家庭住址:"></el-form-item></div>
</el-col>
<el-col :span="20">
<div><el-input v-model="userData.address"></el-input></div>
</el-col>
</el-row>
<el-row>
<el-col :span="4">
<div><el-form-item label="概述:"></el-form-item></div>
</el-col>
<el-col :span="20">
<div><el-input v-model="userData.description" type="textarea"></el-input></div>
</el-col>
</el-row>
<br>
<el-divider content-position="left"><el-button type="primary" @click="updateUser">提交</el-button><el-button @click="dialogFormVisible = false">关闭</el-button></el-divider>
</el-form>
</el-card>
</el-dialog>
</div>
</template>
<script>
import UserDataService from '../../../services/UserDataService'
import { ElMessage } from 'element-plus'
export default {
data () {
return {
users: [],
dialogFormVisible: false,
userData: ''
}
},
methods: {
retrieveUsers () {
UserDataService.getAll()
.then((response) => {
this.users = response.data
console.log(response.data)
})
.catch((e) => {
console.log(e)
})
},
delUser (id) {
console.log(id)
UserDataService.delete(id)
.then(
ElMessage({
message: '删除成功!',
type: 'success',
duration: 1000
}),
setTimeout(() => {
this.$router.push({ name: 'users' })
this.retrieveUsers()
}, 1000)
).catch(e => {
console.log(e)
})
},
editUser (data) {
this.dialogFormVisible = true
this.userData = data
},
updateUser () {
console.log(this.userData.userCN)
UserDataService.update(this.userData.id, this.userData)
.then(
ElMessage({
message: '修改成功!',
type: 'success',
duration: 1000
}),
setTimeout(() => {
this.$router.push({ name: 'users' })
this.retrieveUsers()
}, 1000)
).catch(e => {
console.log(e)
})
this.dialogFormVisible = false
}
},
mounted () {
this.retrieveUsers()
}
}
</script>
<style scoped>
.head {
margin-top: -30px;
}
</style>
- AddUser.vue
<template>
<div>
<el-card
class="box-card"
:body-style="{ padding: '20px', width: '80%', margin: '0 auto' }">
<!-- 卡片头部分 -->
<template #header>
<div>
添加用户信息
</div>
</template>
<!-- 表单字段部分 -->
<el-form label-position="right" label-width="100%">
<el-divider content-position="left">基本信息</el-divider>
<el-row>
<el-col :span="4">
<div><el-form-item label="用户编号:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div><el-input v-model="userData.userId"></el-input></div>
</el-col>
<el-col :span="4">
<div><el-form-item label="用户账号:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div><el-input v-model="userData.userName"></el-input></div>
</el-col>
</el-row>
<el-row>
<el-col :span="4">
<div><el-form-item label="用户密码:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div><el-input v-model="userData.userPass"></el-input></div>
</el-col>
<el-col :span="4">
<div><el-form-item label="确认密码:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div><el-input v-model="userData.reUserPass"></el-input></div>
</el-col>
</el-row>
<el-row>
<el-col :span="4">
<div><el-form-item label="中文名称:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div><el-input v-model="userData.userCN"></el-input></div>
</el-col>
<el-col :span="4">
<div><el-form-item label="用户性别:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div>
<el-radio-group v-model="userData.sex">
<el-radio label="男"></el-radio>
<el-radio label="女"></el-radio>
</el-radio-group>
</div>
</el-col>
</el-row>
<el-divider content-position="left">办公信息</el-divider>
<el-row>
<el-col :span="4">
<div><el-form-item label="移动电话:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div><el-input v-model="userData.mobile"></el-input></div>
</el-col>
<el-col :span="4">
<div><el-form-item label="办公电话:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div><el-input v-model="userData.telNo"></el-input></div>
</el-col>
</el-row>
<el-row>
<el-col :span="4">
<div><el-form-item label="电子邮箱:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div><el-input v-model="userData.email"></el-input></div>
</el-col>
<el-col :span="4">
<div><el-form-item label="房间号码:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div><el-input v-model="userData.roomNO"></el-input></div>
</el-col>
</el-row>
<el-row>
<el-col :span="4">
<div><el-form-item label="是否有效:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div>
<el-radio-group v-model="userData.isEffective">
<el-radio label="是"></el-radio>
<el-radio label="否"></el-radio>
</el-radio-group></div>
</el-col>
<el-col :span="4">
<div><el-form-item label="有效期至:"></el-form-item></div>
</el-col>
<el-col :span="8">
<div>
<el-date-picker type="date" v-model="userData.effectTime" placeholder="选择有效截止日期" style="width: 100%"></el-date-picker>
</div>
</el-col>
</el-row>
<el-divider content-position="left">其他信息</el-divider>
<el-row>
<el-col :span="4">
<div><el-form-item label="家庭住址:"></el-form-item></div>
</el-col>
<el-col :span="20">
<div><el-input v-model="userData.address"></el-input></div>
</el-col>
</el-row>
<el-row>
<el-col :span="4">
<div><el-form-item label="概述:"></el-form-item></div>
</el-col>
<el-col :span="20">
<div><el-input v-model="userData.description" type="textarea"></el-input></div>
</el-col>
</el-row>
<el-divider content-position="left"><el-button type="primary" @click="onSubmit">提交</el-button><el-button @click="resetForm">重置</el-button></el-divider>
</el-form>
</el-card>
</div>
</template>
<script>
import UserDataService from '../../../services/UserDataService'
import { ElMessage } from 'element-plus'
export default {
data () {
return {
test: '123',
userData: {
userId: '',
userName: '',
userPass: '',
userCN: '',
sex: '男',
mobile: '',
telNo: '',
email: '',
roomNO: '',
address: '',
effectTime: '2022/01/01',
description: '',
isEffective: '是',
createdAt: '',
updatedAt: ''
}
}
},
methods: {
onSubmit () {
var userInfo = {
userId: this.userData.userId,
userName: this.userData.userName,
userPass: this.userData.userPass,
userCN: this.userData.userCN,
sex: this.userData.sex,
mobile: this.userData.mobile,
telNo: this.userData.telNo,
email: this.userData.email,
roomNO: this.userData.roomNO,
address: this.userData.address,
effectTime: this.userData.effectTime,
description: this.userData.description,
isEffective: this.userData.isEffective === '是' ? '1' : '0',
createdAt: '2022-01-01',
updatedAt: '2022-01-01'
}
UserDataService.create(userInfo)
.then(res => {
console.log(res.data)
ElMessage({
message: '提交成功!',
type: 'success',
duration: 1000
})
setTimeout(() => {
this.$router.push({ name: 'users' })
}, 1000)
})
.catch(e => {
console.log(e)
})
},
resetForm () {
this.userData = {}
}
}
}
</script>
11、目录结构
12、运行效果图
- 用户列表:
- 添加用户:
- 修改用户:
注意:有些方法尚未实现,表单缺少验证功能,注意修改后端的端口信息server.js
const express = require("express");
const cors = require("cors");
const app = express();
var corsOptions = {
origin: "http://localhost:3000"
};
app.use(cors(corsOptions));
// 解析内容类型为:application/json 的请求
app.use(express.json());
// 解析内容类型为:application/x-www-form-urlencoded 的请求
app.use(express.urlencoded({ extended: true }));
const db = require("./app/models");
db.sequelize.sync();
/**
* 通过models实例创建数据库表时使用
db.sequelize.sync({ force: true }).then(() => {
console.log("删除并且重新同步数据库!!!");
});
*/
// 简单路由
app.get("/", (req, res) => {
res.json({ message: "欢迎来到我的应用!!!" });
});
require("./app/routes/user.routes")(app);
// 设置端口, 监听请求
const PORT = process.env.PORT || 9000;
app.listen(PORT, () => {
console.log(`服务器正在运行,端口为: ${PORT}.`);
});