赞
踩
后端采用 Pycharm 编辑器,目录结构如下
依赖文件
Flask==1.1.2
Flask-Cors==3.0.7
模拟数据库 CRUD,以及 API 路由操作
import uuid from flask import Flask, jsonify, request from flask_cors import CORS BOOKS = [ { 'id': uuid.uuid4().hex, 'title': 'On the Road', 'author': 'Jack Kerouac', 'read': True }, { 'id': uuid.uuid4().hex, 'title': 'Harry Potter and the Philosopher\'s Stone', 'author': 'J. K. Rowling', 'read': False }, { 'id': uuid.uuid4().hex, 'title': 'Green Eggs and Ham', 'author': 'Dr. Seuss', 'read': True } ] # configuration DEBUG = True # instantiate the app app = Flask(__name__) app.config.from_object(__name__) # enable CORS CORS(app, resources={r'/*': {'origins': '*'}}) def remove_book(book_id): for book in BOOKS: if book['id'] == book_id: BOOKS.remove(book) return True return False # sanity check route @app.route('/ping', methods=['GET']) def ping_pong(): return jsonify('pong!') @app.route('/books', methods=['GET', 'POST']) def all_books(): response_object = {'status': 'success'} if request.method == 'POST': post_data = request.get_json() BOOKS.append({ 'id': uuid.uuid4().hex, 'title': post_data.get('title'), 'author': post_data.get('author'), 'read': post_data.get('read') }) response_object['message'] = 'Book added!' else: response_object['books'] = BOOKS return jsonify(response_object) @app.route('/books/<book_id>', methods=['PUT', 'DELETE']) def single_book(book_id): response_object = {'status': 'success'} if request.method == 'PUT': post_data = request.get_json() remove_book(book_id) BOOKS.append({ 'id': uuid.uuid4().hex, 'title': post_data.get('title'), 'author': post_data.get('author'), 'read': post_data.get('read') }) response_object['message'] = 'Book updated!' if request.method == 'DELETE': res = remove_book(book_id) if res: response_object['message'] = 'Book removed!' else: response_object['message'] = 'Did not find the id!' return jsonify(response_object) if __name__ == '__main__': app.run()
前端采用 VSCode 编辑器,目录结构如下
<template>
<div>
<b-alert variant="success" show>{{ message }}</b-alert>
<br>
</div>
</template>
<script>
export default {
props: ['message'],
};
</script>
<template> <div class="container"> <div class="row"> <div class="col-sm-10"> <h1>Books</h1> <hr><br><br> <alert :message=message v-if="showMessage"></alert> <button type="button" class="btn btn-success btn-sm" v-b-modal.book-modal>Add Book</button> <br><br> <table class="table table-hover"> <thead> <tr> <th scope="col">Title</th> <th scope="col">Author</th> <th scope="col">Read?</th> <th></th> </tr> </thead> <tbody> <tr v-for="(book, index) in books" :key="index"> <td>{{ book.title }}</td> <td>{{ book.author }}</td> <td> <span v-if="book.read">Yes</span> <span v-else>No</span> </td> <td> <div class="btn-group" role="group"> <button type="button" class="btn btn-warning btn-sm" v-b-modal.book-update-modal @click="editBook(book)"> Update </button> <button type="button" class="btn btn-danger btn-sm" @click="onDeleteBook(book)"> Delete </button> </div> </td> </tr> </tbody> </table> </div> </div> <b-modal ref="addBookModal" id="book-modal" title="Add a new book" hide-footer> <b-form @submit="onSubmit" @reset="onReset" class="w-100"> <b-form-group id="form-title-group" label="Title:" label-for="form-title-input"> <b-form-input id="form-title-input" type="text" v-model="addBookForm.title" required placeholder="Enter title"> </b-form-input> </b-form-group> <b-form-group id="form-author-group" label="Author:" label-for="form-author-input"> <b-form-input id="form-author-input" type="text" v-model="addBookForm.author" required placeholder="Enter author"> </b-form-input> </b-form-group> <b-form-group id="form-read-group"> <b-form-checkbox-group v-model="addBookForm.read" id="form-checks"> <b-form-checkbox value="true">Read?</b-form-checkbox> </b-form-checkbox-group> </b-form-group> <b-button-group> <b-button type="submit" variant="primary">Submit</b-button> <b-button type="reset" variant="danger">Reset</b-button> </b-button-group> </b-form> </b-modal> <b-modal ref="editBookModal" id="book-update-modal" title="Update" hide-footer> <b-form @submit="onSubmitUpdate" @reset="onResetUpdate" class="w-100"> <b-form-group id="form-title-edit-group" label="Title:" label-for="form-title-edit-input"> <b-form-input id="form-title-edit-input" type="text" v-model="editForm.title" required placeholder="Enter title"> </b-form-input> </b-form-group> <b-form-group id="form-author-edit-group" label="Author:" label-for="form-author-edit-input"> <b-form-input id="form-author-edit-input" type="text" v-model="editForm.author" required placeholder="Enter author"> </b-form-input> </b-form-group> <b-form-group id="form-read-edit-group"> <b-form-checkbox-group v-model="editForm.read" id="form-checks"> <b-form-checkbox value="true">Read?</b-form-checkbox> </b-form-checkbox-group> </b-form-group> <b-button-group> <b-button type="submit" variant="primary">Update</b-button> <b-button type="reset" variant="danger">Cancel</b-button> </b-button-group> </b-form> </b-modal> </div> </template> <script> import axios from 'axios'; import Alert from './Alert.vue'; export default { data() { return { books: [], addBookForm: { title: '', author: '', read: [], }, message: '', showMessage: false, editForm: { id: '', title: '', author: '', read: [], }, }; }, components: { alert: Alert, }, methods: { getBooks() { const path = 'http://localhost:5000/books'; axios.get(path) .then((res) => { this.books = res.data.books; }) .catch((error) => { // eslint-disable-next-line console.error(error); }); }, addBook(payload) { const path = 'http://localhost:5000/books'; axios.post(path, payload) .then(() => { this.getBooks(); this.message = 'Book added!'; this.showMessage = true; }) .catch((error) => { // eslint-disable-next-line console.log(error); this.getBooks(); }); }, initForm() { this.addBookForm.title = ''; this.addBookForm.author = ''; this.addBookForm.read = []; this.editForm.id = ''; this.editForm.title = ''; this.editForm.author = ''; this.editForm.read = []; }, onSubmit(evt) { evt.preventDefault(); this.$refs.addBookModal.hide(); let read = false; if (this.addBookForm.read[0]) read = true; const payload = { title: this.addBookForm.title, author: this.addBookForm.author, read, // property shorthand }; this.addBook(payload); this.initForm(); }, onReset(evt) { evt.preventDefault(); this.$refs.addBookModal.hide(); this.initForm(); }, editBook(book) { this.editForm = book; }, onSubmitUpdate(evt) { evt.preventDefault(); this.$refs.editBookModal.hide(); let read = false; if (this.editForm.read[0]) read = true; const payload = { title: this.editForm.title, author: this.editForm.author, read, }; this.updateBook(payload, this.editForm.id); }, updateBook(payload, bookID) { const path = `http://localhost:5000/books/${bookID}`; axios.put(path, payload) .then(() => { this.getBooks(); this.message = 'Book updated!'; this.showMessage = true; }) .catch((error) => { // eslint-disable-next-line console.error(error); this.getBooks(); }); }, onResetUpdate(evt) { evt.preventDefault(); this.$refs.editBookModal.hide(); this.initForm(); this.getBooks(); // why? }, removeBook(bookID) { const path = `http://localhost:5000/books/${bookID}`; axios.delete(path) .then(() => { this.getBooks(); this.message = 'Book removed!'; this.showMessage = true; }) .catch((error) => { // eslint-disable-next-line console.error(error); this.getBooks(); }); }, onDeleteBook(book) { this.removeBook(book.id); }, }, created() { this.getBooks(); }, }; </script>
<template> <div class="container"> <button type="button" class="btn btn-primary">{{ msg }}</button> </div> </template> <script> import axios from 'axios'; export default { name: 'Ping', data() { return { msg: '', }; }, methods: { getMessage() { const path = 'http://localhost:5000/ping'; axios.get(path) .then((res) => { this.msg = res.data; }) .catch((error) => { // eslint-disable-next-line console.error(error); }); }, }, created() { this.getMessage(); }, }; </script>
<template>
<div id="app">
<router-view/>
</div>
</template>
<style>
#app {
margin-top: 60px
}
</style>
import Vue from 'vue'; import Router from 'vue-router'; import Books from './components/Books.vue'; import Ping from './components/Ping.vue'; Vue.use(Router); export default new Router({ mode: 'history', base: process.env.BASE_URL, routes: [ { path: '/', name: 'Books', component: Books, }, { path: '/ping', name: 'Ping', component: Ping, }, ], });
import 'bootstrap/dist/css/bootstrap.css';
import BootstrapVue from 'bootstrap-vue';
import Vue from 'vue';
import App from './App.vue';
import router from './router';
Vue.use(BootstrapVue);
Vue.config.productionTip = false;
new Vue({
router,
render: h => h(App),
}).$mount('#app');
src
上级目录)下执行以下两个命令cnpm install
cnpm run serve
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。