Vue3+Strapi CRUD演示代码(进阶版)
文章目录
前些天写过一个Vue3+strapi的crud演示,那一版非常简单直接使用CDN引入核心文件,也就是最终一个html作为程序入口,接下来我用了vue cli来做了一个webpack版本的演示,这一版相对来说更高级一些,文件结构也更工程化,维护性也更强。




服务端的准备
本内容主要着重前端Vuejs3 CRUD请求的实现,后端部分我依旧使用了Strapi,其实用什么都可以,无所谓了 只要能拿到正确的API结构
如果使用strapi,需要新建一个这样的content-type
依赖和文件结构
"dependencies": {
"@popperjs/core": "^2.10.2",
"axios": "^0.24.0",
"bootstrap": "^5.1.3",
"core-js": "^3.6.5",
"jquery": "^3.6.0",
"vue": "^3.0.0",
"vue-router": "^4.0.12"
}
文件结构
文件说明:
– package.json 包含核心程序模块: vue
, vue-router
, axios
, bootstrap
.
– 共又3个核心组件component: TutorialsList
, Tutorial
, AddTutorial
.
– router.js 为组件component定义路由
– http-common.js 初始化axios并配置服务端请求地址,headers等相关内容
– TutorialDataService
封装了所有服务端产生的HTTP请求方法
– vue.config.js 配置服务启动端口
components/AddTutorial.vue
添加记录的表单
<template>
<div class="submit-form">
<div v-if="!submitted">
<div class="form-group">
<label for="title">Title</label>
<input
type="text"
class="form-control"
id="title"
required
v-model="tutorial.title"
name="title"
/>
</div>
<div class="form-group">
<label for="description">Description</label>
<input
class="form-control"
id="description"
required
v-model="tutorial.description"
name="description"
/>
</div>
<button @click="saveTutorial" class="btn btn-success">Submit</button>
</div>
<div v-else>
<h4>You submitted successfully!</h4>
<button class="btn btn-success" @click="newTutorial">Add</button>
</div>
</div>
</template>
<script>
import TutorialDataService from "../services/TutorialDataService";
export default {
name: "add-tutorial",
data() {
return {
tutorial: {
id: null,
title: "",
description: "",
published: false
},
submitted: false
};
},
methods: {
saveTutorial() {
var data = {
title: this.tutorial.title,
description: this.tutorial.description
};
TutorialDataService.create(data)
.then(response => {
this.tutorial.id = response.data.id;
console.log(response.data);
this.submitted = true;
})
.catch(e => {
console.log(e);
});
},
newTutorial() {
this.submitted = false;
this.tutorial = {};
}
}
};
</script>
<style>
.submit-form {
max-width: 300px;
margin: auto;
}
</style>
components/Tutorial.vue
单条记录的查看和修改
<template>
<div v-if="currentTutorial" class="edit-form">
<h4>Tutorial</h4>
<form>
<div class="form-group">
<label for="title">Title</label>
<input type="text" class="form-control" id="title"
v-model="currentTutorial.title"
/>
</div>
<div class="form-group">
<label for="description">Description</label>
<input type="text" class="form-control" id="description"
v-model="currentTutorial.description"
/>
</div>
<div class="form-group">
<label><strong>Status:</strong></label>
{{ currentTutorial.published ? "Published" : "Pending" }}
</div>
</form>
<button class="badge badge-primary mr-2"
v-if="currentTutorial.published"
@click="updatePublished(false)"
>
UnPublish
</button>
<button v-else class="badge bg-primary mr-2"
@click="updatePublished(true)"
>
Publish
</button>
<button class="badge bg-danger mr-2"
@click="deleteTutorial"
>
Delete
</button>
<button type="submit" class="badge bg-success"
@click="updateTutorial"
>
Update
</button>
<p>{{ message }}</p>
</div>
<div v-else>
<br />
<p>Please click on a Tutorial...</p>
</div>
</template>
<script>
import TutorialDataService from "../services/TutorialDataService";
export default {
name: "tutorial",
data() {
return {
currentTutorial: null,
message: ''
};
},
methods: {
getTutorial(id) {
TutorialDataService.get(id)
.then(response => {
this.currentTutorial = response.data;
console.log(response.data);
})
.catch(e => {
console.log(e);
});
},
updatePublished(status) {
var data = {
id: this.currentTutorial.id,
title: this.currentTutorial.title,
description: this.currentTutorial.description,
published: status
};
TutorialDataService.update(this.currentTutorial.id, data)
.then(response => {
console.log(response.data);
this.currentTutorial.published = status;
this.message = 'The status was updated successfully!';
})
.catch(e => {
console.log(e);
});
},
updateTutorial() {
TutorialDataService.update(this.currentTutorial.id, this.currentTutorial)
.then(response => {
console.log(response.data);
this.message = 'The tutorial was updated successfully!';
})
.catch(e => {
console.log(e);
});
},
deleteTutorial() {
TutorialDataService.delete(this.currentTutorial.id)
.then(response => {
console.log(response.data);
this.$router.push({ name: "tutorials" });
})
.catch(e => {
console.log(e);
});
}
},
mounted() {
this.message = '';
this.getTutorial(this.$route.params.id);
}
};
</script>
<style>
.edit-form {
max-width: 300px;
margin: auto;
}
</style>
components/TutorialsList.vue
所有记录的列表
<template>
<div class="list row">
<div class="col-md-8">
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="Search by title"
v-model="title"/>
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button"
@click="searchTitle"
>
Search
</button>
</div>
</div>
</div>
<div class="col-md-6">
<h4>Tutorials List</h4>
<ul class="list-group">
<li class="list-group-item"
:class="{ active: index == currentIndex }"
v-for="(tutorial, index) in tutorials"
:key="index"
@click="setActiveTutorial(tutorial, index)"
>
{{ tutorial.title }}
</li>
</ul>
<button class="m-3 btn btn-sm btn-danger" @click="removeAllTutorials">
Remove All
</button>
</div>
<div class="col-md-6">
<div v-if="currentTutorial">
<h4>Tutorial</h4>
<div>
<label><strong>Title:</strong></label> {{ currentTutorial.title }}
</div>
<div>
<label><strong>Description:</strong></label> {{ currentTutorial.description }}
</div>
<div>
<label><strong>Status:</strong></label> {{ currentTutorial.published ? "Published" : "Pending" }}
</div>
<router-link :to="'/tutorials/' + currentTutorial.id" class="badge bg-secondary">Edit</router-link>
</div>
<div v-else>
<br />
<p>Please click on a Tutorial...</p>
</div>
</div>
</div>
</template>
<script>
import TutorialDataService from "../services/TutorialDataService";
export default {
name: "tutorials-list",
data() {
return {
tutorials: [],
currentTutorial: null,
currentIndex: -1,
title: ""
};
},
methods: {
retrieveTutorials() {
TutorialDataService.getAll()
.then(response => {
this.tutorials = response.data;
console.log(response.data);
})
.catch(e => {
console.log(e);
});
},
refreshList() {
this.retrieveTutorials();
this.currentTutorial = null;
this.currentIndex = -1;
},
setActiveTutorial(tutorial, index) {
this.currentTutorial = tutorial;
this.currentIndex = tutorial ? index : -1;
},
removeAllTutorials() {
TutorialDataService.deleteAll()
.then(response => {
console.log(response.data);
this.refreshList();
})
.catch(e => {
console.log(e);
});
},
searchTitle() {
TutorialDataService.findByTitle(this.title)
.then(response => {
this.tutorials = response.data;
this.setActiveTutorial(null);
console.log(response.data);
})
.catch(e => {
console.log(e);
});
}
},
mounted() {
this.retrieveTutorials();
}
};
</script>
<style>
.list {
text-align: left;
max-width: 750px;
margin: auto;
}
</style>
services/TutorialDataService.js
所有Axios的http数据请求的方法封装
import http from "../http-common";
class TutorialDataService {
getAll() {
return http.get("/tutorials");
}
get(id) {
return http.get(`/tutorials/${id}`);
}
create(data) {
return http.post("/tutorials", data);
}
update(id, data) {
return http.put(`/tutorials/${id}`, data);
}
delete(id) {
return http.delete(`/tutorials/${id}`);
}
deleteAll() {
return http.delete(`/tutorials`);
}
findByTitle(title) {
return http.get(`/tutorials?title_contains=${title}`);
}
}
export default new TutorialDataService();
App.vue
项目启动入口
<template>
<div id="app">
<nav class="navbar navbar-expand navbar-dark bg-dark">
<router-link to="/" class="navbar-brand">bezKoder</router-link>
<div class="navbar-nav mr-auto">
<li class="nav-item">
<router-link to="/tutorials" class="nav-link">Tutorials</router-link>
</li>
<li class="nav-item">
<router-link to="/add" class="nav-link">Add</router-link>
</li>
</div>
</nav>
<div class="container mt-3">
<router-view />
</div>
</div>
</template>
<script>
export default {
name: "app"
};
</script>
http-common.js
服务端接口相关配置
import axios from "axios";
export default axios.create({
baseURL: "http://localhost:4000/",
headers: {
"Content-type": "application/json"
}
});
main.js
导入重要依赖
import { createApp } from 'vue'
import App from './App.vue'
import 'bootstrap'
import 'bootstrap/dist/css/bootstrap.min.css'
import router from './router'
createApp(App).use(router).mount('#app')
router.js
组件的路由配置
import { createWebHistory, createRouter } from "vue-router";
const routes = [
{
path: "/",
alias: "/tutorials",
name: "tutorials",
component: () => import("./components/TutorialsList")
},
{
path: "/tutorials/:id",
name: "tutorial-details",
component: () => import("./components/Tutorial")
},
{
path: "/add",
name: "add",
component: () => import("./components/AddTutorial")
}
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;
vue.config.js
配置项目运行端口
module.exports = {
devServer: {
port: 8081
}
}