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 } }