這篇文章,給大家?guī)硪粋€列表查詢的功能,從前端到后端的一個綜合案例實戰(zhàn)。
采用vue3作為前端開發(fā),nodejs作為后端開發(fā)。
首先我們先來看一下完成的頁面效果。點擊分頁,可以切換到上一頁、下一頁。搜索框可以進行模糊查詢。
后端項目開發(fā)
好的,那么看完項目的演示,我們先來開發(fā)一下后端的邏輯。
后端需要開發(fā)的功能那個很簡單,就是一個列表分頁查詢的接口。當然也可以用java語言去開發(fā),我們這里就直接用nodejs作為一個后端語言去開發(fā)列表分頁查詢的接口。
1.創(chuàng)建一個后端的項目
(1)初始化項目
npm init -y
(2)下載express框架,對于express其實就是創(chuàng)建http服務的一款框架
cnpm i express@4.17.3 -S
(3)安裝解析接收參數的中間件
cnpm i body-parser@1.19.2 -S
(4)下載跨域cors配置
cnpm i cors@2.8.5 -S
(5)創(chuàng)建app.js
/**
* 統一入口
*/
//引入express,配置app
const express = require("express");
const app = express();
//配置post請求的參數解析
const bodyParser = require("body-parser");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
//配置跨域設置
const cors = require("cors");
app.use(cors());
//錯誤中間件配置
app.use((err, req, res, next) => {
console.log(err);
res.send({ code: 500, msg: err.message, data: null });
});
//啟動8090端口監(jiān)聽的服務
app.listen(8090, () => {
console.log("server run in http://127.0.0.1:8090");
});
控制臺輸入node app.js,正常運行
mac@bogon product_server % node app.js
server run in http://127.0.0.1:8090
2.配置數據庫
(1)linux部署mysql數據庫
我們采用docker部署,大家可以在網上找一片博文去部署一下,這里就不再過多的去寫部署步驟了。
docker run -p 3306:3306 --name mysql \
-v /usr/local/docker/mysql/conf:/etc/mysql \
-v /usr/local/docker/mysql/logs:/var/log/mysql \
-v /usr/local/docker/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-d mysql:5.7
部署完成之后,采用可視化工具連接。
創(chuàng)建video表,腳本給大家提供好。
CREATE TABLE `video` (
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '課程id',
`title` varchar(524) DEFAULT NULL COMMENT '視頻標題',
`course_img` varchar(524) DEFAULT NULL COMMENT '封面圖',
`price` varchar(11) DEFAULT NULL COMMENT '價格,分',
`point` double(11,2) DEFAULT '8.70' COMMENT '默認8.7,最高10分',
`level` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '課程分類',
`del` int DEFAULT '0' COMMENT '是否刪除',
`learn_num` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb3;
INSERT INTO test.video
(id, title, course_img, price, `point`, `level`, del, learn_num)
VALUES(1, 'MCA高級架構師', 'https://oss-cdn.mashibing.com/default/2ac035f1b09412a514833d72bd23629b.png', '109', 9.8, '高級', 0, '8372');
INSERT INTO test.video
(id, title, course_img, price, `point`, `level`, del, learn_num)
VALUES(4, 'Java后端工程師', 'https://oss-cdn.mashibing.com/default/ff0dbc7d6077b9656e3f68f8775d80de.png', '39', 9.2, '高級', 0, '2389');
INSERT INTO test.video
(id, title, course_img, price, `point`, `level`, del, learn_num)
VALUES(5, 'Python全系列大師課', 'https://oss-cdn.mashibing.com/default/e1b96583ce902f8475d50fccd00583f3.png', '49', 9.4, '高級', 0, '1231');
INSERT INTO test.video
(id, title, course_img, price, `point`, `level`, del, learn_num)
VALUES(6, 'AIoT智能物聯網 ', 'https://oss-cdn.mashibing.com/default/fdf4171e34e95446c1faaab9780a6a3c.png', '29', 9.2, '高級', 0, '12331');
INSERT INTO test.video
(id, title, course_img, price, `point`, `level`, del, learn_num)
VALUES(7, 'AI人工智能算法班', 'https://oss-cdn.mashibing.com/default/b1519e27e526abce071077a46155debe.png', '29', 9.4, '高級', 0, '43123');
INSERT INTO test.video
(id, title, course_img, price, `point`, `level`, del, learn_num)
VALUES(8, 'Python全棧工程師', 'https://ksimage-cdn.mashibing.com/ee30a77db459480ab9e9dbca4110abb7.png', '3699', 9.9, '高級', 0, '3241');
INSERT INTO test.video
(id, title, course_img, price, `point`, `level`, del, learn_num)
VALUES(9, '網絡安全大師課', 'https://oss-cdn.mashibing.com/default/4839c97b8638ef5d01d55ee945f73346.png', '1699', 9.9, '高級', 0, '2371');
INSERT INTO test.video
(id, title, course_img, price, `point`, `level`, del, learn_num)
VALUES(10, 'Web前端架構師', 'https://oss-cdn.mashibing.com/default/56d51db7d4e728b4bdd826871b31fcdd.png', '129', 9.9, '高級', 0, '43983');
INSERT INTO test.video
(id, title, course_img, price, `point`, `level`, del, learn_num)
VALUES(11, '大數據架構師', 'https://oss-cdn.mashibing.com/default/89c03f0a7d557932b2c916896f840ac0.png', '158', 9.9, '高級', 0, '8372');
INSERT INTO test.video
(id, title, course_img, price, `point`, `level`, del, learn_num)
VALUES(12, '嵌入式物聯網工程師', 'https://oss-cdn.mashibing.com/default/8a0d860ae085d665cba6500037a42660.png', '189', 9.9, '高級', 0, '3874');
INSERT INTO test.video
(id, title, course_img, price, `point`, `level`, del, learn_num)
VALUES(13, '云原生架構師', 'https://oss-cdn.mashibing.com/default/0b611f56605230afa78e36d3fc28d7fe.png', '98', 9.9, '高級', 0, '2321');
INSERT INTO test.video
(id, title, course_img, price, `point`, `level`, del, learn_num)
VALUES(14, 'AI人工智能零基礎入門班 ', 'https://oss-cdn.mashibing.com/default/93684399167651b31ed02224cdbc6f8a.jpg', '89', 9.9, '高級', 0, '32431');
INSERT INTO test.video
(id, title, course_img, price, `point`, `level`, del, learn_num)
VALUES(15, '游戲后端架構師', 'https://ksimage-cdn.mashibing.com/c6726d23750140fa9fb917172462e427.png', '99', 9.9, '高級', 0, '23543');
INSERT INTO test.video
(id, title, course_img, price, `point`, `level`, del, learn_num)
VALUES(16, 'C++ 軟件開發(fā)工程師', 'https://oss-cdn.mashibing.com/default/f2fd73a74fa6465e3feaf41bb756457a.png', '1699', 9.9, '高級', 0, '12332');
INSERT INTO test.video
(id, title, course_img, price, `point`, `level`, del, learn_num)
VALUES(17, '數據分析全崗位實戰(zhàn)班', 'https://oss-cdn.mashibing.com/default/440538433aa74ede1fbfe2945ec060c7.jpg', '68', 9.9, '高級', 0, '12343');
INSERT INTO test.video
(id, title, course_img, price, `point`, `level`, del, learn_num)
VALUES(18, '大廠算法特訓班 ', 'https://oss-cdn.mashibing.com/default/412befe796fed3a83d695185001944fb.jpg', '79', 9.2, '高級', 0, '2341');
(3)下載mysql的依賴
cnpm i mysql@2.18.1 -S
(4)配置數據庫連接
//引入mysql配置
const mysql = require('mysql');
//創(chuàng)建db實例
const db = mysql.createPool({
host: '192.168.140.134',
user: 'root',
password: '123456',
database: 'test',
});
//導出
module.exports = db;
3.編寫課程查詢接口
(1)創(chuàng)建course_controller.js
//引入db配置
const db = require("../config/db_config");
exports.page = (req, res) => {
//獲取前端的參數
let { title, page, size } = req.query;
page = (page - 1) * size;
if (title.length == 0) {
title = "";
} else {
title = `and title like '%${title}%'`;
}
//查詢課程列表sql
const pageSql = `select * from video where del=0 ${title} order by id limit ${page},${size}`;
//查詢課程總數的sql
const totalSql = `select count(*) as total from video where del=0 ${title}`;
db.query(pageSql, (err, pageData) => {
if (err) {
throw new Error(err.message);
}
db.query(totalSql, (err, count) => {
if (err) {
throw new Error(err.message);
}
res.send({
code: 200,
msg: "",
data: {
data: pageData,
total: count[0].total,
pages:0
},
});
});
});
};
(2)創(chuàng)建router下的course.js
const express = require('express');
const router = express.Router();
const course_controller = require("../controller/course_controller");
//查詢視頻列表
router.get("/api/v1/page", course_controller.page);
//導出路由
module.exports = router;
(3)app.js配置路由
//配置路由
const productRouter = require("./router/course.js");
app.use("/course", productRouter);
整體的目錄結構:
(4)訪問接口測試
http://127.0.0.1:8090/course/api/v1/page?page=1&size=10&title
前端項目開發(fā)
前端采用vue3+elementUI開發(fā)。
1.前端項目搭建
(1)安裝腳手架vue/cli
npm install -g @vue/cli@5.0.4
(2)下載elementUI組件
cnpm install element-plus@2.1.11 -S
cnpm install -D unplugin-vue-components@0 unplugin-auto-import@0
(3)安裝less預處理器
cnpm i less@4.1.2 less-loader@7 -S
(4)搭建前端項目
vue create product_web
(5)配置vue.config.js
const { defineConfig } = require('@vue/cli-service');
const AutoImport = require('unplugin-auto-import/webpack');
const Components = require('unplugin-vue-components/webpack');
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers');
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave: false, //關閉ESlint校驗
configureWebpack: {
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
},
});
(6)編寫公共樣式
html,
body {
padding: 0;
margin: 0;
background-color: #f5f5f5;
}
html,
body,
#app {
height: 100%;
}
input {
border: none;
outline: none;
}
button {
border: none;
outline: none;
}
a {
text-decoration: none;
color: #333;
}
li {
list-style-type: none;
}
(7)安裝路由插件
cnpm i vue-router@4.0.14 -S
(8)element-plus圖標自動引入配置,公共樣式引入,以及路由引入
import { createApp } from 'vue'
import App from './App.vue'
import './common/base.css';
import * as elementIcons from '@element-plus/icons-vue';
import router from './router/index';
const app = createApp(App);
for (let iconName in elementIcons) {
app.component(iconName, elementIcons[iconName]);
}
app.use(router).mount('#app');
(9)創(chuàng)建路由文件
import { createRouter, createWebHashHistory } from "vue-router";
//路由配置
const router = createRouter({
history: createWebHashHistory(), //選擇hash路由
routes: [
{
path: "/",
redirect: "/home",
},
{
path: "/home",
component: () => import("../views/Home"),
}
],
});
export default router;
(10)創(chuàng)建views文件夾,創(chuàng)建Home.vue文件
先保證項目不報錯。
2.編寫列表頁面
(1)首先編寫Home.vue文件,這里涉及接口的調用下面我們在編寫這個接口的請求
<template>
<div class="main">
<el-form>
<el-form-item>
<el-input v-model.trim="inputValue" placeholder="請輸入內容"></el-input>
</el-form-item>
<el-button type="primary" @click="handleClick">查詢</el-button>
</el-form>
<Table :list="data.list" />
<Pagination :currentChange="currentChange"></Pagination>
</div>
</template>
<script setup>
import Table from "./components/Table.vue";
import Pagination from "./components/Pagination.vue";
import { reactive, ref,onMounted } from "vue";
import { getCourse } from "../api/index";
/**
* 初始化的數據
*/
const data = reactive({
list: [],
page: 1, //默認展示第一頁
total: 5, //課程總數
});
//onMounted首次加載調用一次接口
onMounted(() => {
getCourseData();
});
/**
* 課程列表數據獲取和課程類目切換邏輯
*/
const getCourseData = async (query) => {
const title = query?.title || "";
const page = query?.page || 1;
const size = query?.size || 5;
const res = await getCourse({ title, page, size });
//篩選符合分類的課程
data.list = res?.data.data.data;
data.total = res?.data.data.total;
};
/**
* 分頁的邏輯
*/
const currentChange = (val) => {
if (val === "pre") {
if (data.page > 1) {
data.page--;
} else {
ElMessage({
message: "已經是第一頁了?。?!",
type: "warning",
showClose: true,
});
}
}
if (val === "next") {
if (data.page < Math.ceil(data.total / 5)) {
data.page++;
} else {
ElMessage({
message: "已經是最后一頁了?。?!",
type: "warning",
showClose: true,
});
}
}
//請求課程的接口
getCourseData({ title: data.title, page: data.page });
};
/**
* 搜索框的邏輯
*/
const inputValue = ref("");
//搜索的按鈕
const handleClick = () => {
getCourseData({ title: inputValue.value });
ElMessage({
message: "查詢成功",
type: "success",
});
};
</script>
<style lang="less" scoped>
.el-form {
display: flex;
}
.main {
background-color: #fff;
padding: 20px;
flex: 1;
display: flex;
flex-direction: column;
.input-with-select {
width: 400px;
margin-bottom: 40px;
}
}
:deep(.el-table__header-wrapper) {
position: fixed;
z-index: 20;
}
:deep(.el-table__inner-wrapper) {
overflow: hidden;
}
:deep(.el-table__body-wrapper) {
margin-top: 40px;
}
:deep(.el-input__inner) {
width: 300px;
margin-right: 10px;
}
:deep(.warning-row) {
--el-table-tr-bg-color: var(--el-color-warning-light-9) !important;
height: 140px !important;
}
.table {
height: 80vh;
width: 98vw;
overflow: hidden;
overflow-y: scroll;
text-align: center;
}
.table::-webkit-scrollbar {
display: none;
}
</style>
這里面有兩個組件需要創(chuàng)建一下
Pagination.vue
<template>
<div class="pagination">
<div class="pre" @click="currentChange('pre')">上一頁</div>
<div class="next" @click="currentChange('next')">下一頁</div>
</div>
</template>
<script setup>
import { defineProps } from 'vue';
const { currentChange } = defineProps(['currentChange'])
</script>
<style lang='less' scoped>
.pagination {
display: flex;
justify-content: center;
margin-top: 20px;
color: #fff;
.pre {
background-color: #409eff;
margin-right: 10px;
padding: 5px;
cursor:pointer;
}
.next {
padding: 5px;
background-color: #409eff;
cursor:pointer;
}
}
</style>
Table.vue
<template>
<div class="table">
<el-table :data="list">
<el-table-column prop="course_img" label="圖片">
<template #default="scope">
<img :src="scope.row.course_img" class="courseImg-img">
</template>
</el-table-column>
<el-table-column prop="title" label="標題">
</el-table-column>
<el-table-column prop="price" label="價格">
</el-table-column>
<el-table-column prop="point" label="評分">
</el-table-column>
<el-table-column prop="level" label="級別">
</el-table-column>
<el-table-column prop="learn_num" label="學習人數">
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button type="primary">
編輯
</el-button>
<el-popconfirm title="確定要刪除該課程嗎?">
<template #reference>
<el-button type="danger">刪除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup>
import { defineProps } from 'vue';
const { list } = defineProps(['list'])
</script>
<style lang='less' scoped>
.courseImg-img {
width: 150px;
height: 100px;
}
</style>
3.創(chuàng)建接口請求
(1)創(chuàng)建request.js
import axios from 'axios';
/**
* 創(chuàng)建axios實例
*/
const ENV = process.env.NODE_ENV;
const host =
ENV === 'development' ? 'http://127.0.0.1:8090' : 'http://192.168.140.134:8090';
const service = axios.create({
baseURL: host,
timeout: '3000',
});
/**
* 封裝請求函數
*/
const request = (options) => {
if (options.method === 'get') {
options.params = options.data;
}
return service(options);
};
export default request;
(2)創(chuàng)建api中index.js
import request from '../utils/request';
/**
* 課程列表數據接口
*/
export const getCourse = (data) => {
return request({ method: 'get', url: '/course/api/v1/page', data });
};
4.啟動項目
npm run serve
當問頁面
Ok,完成。源代碼博主放在主頁的資源上了,需要的可以下載哦,記得給博主三連??!文章來源:http://www.zghlxwxcb.cn/news/detail-736024.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-736024.html
到了這里,關于【案例實戰(zhàn)】NodeJS+Vue3+MySQL實現列表查詢功能的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!