点击蓝字关注△ 回复“1024”领取福利大礼包
接上回,现在我们开始构建CRUD应用程序。
我们的目标是设计一个后端RESTful API,由Python和Flask提供支持。API本身应该遵循RESTful设计原则,使用基本的HTTP请求方式:GET、POST、PUT和DELETE来完成。
我们还将用Vue开发一个前端应用程序,使用后端提供的接口API:
添加一个GET请求的接口服务
在app.py中,添加一个书籍列表,这是一些假数据,真实情况应该从数据库获取:
代码语言:javascript复制BOOKS = [
{
'title': 'On the Road',
'author': 'Jack Kerouac',
'read': True
},
{
'title': 'Harry Potter and the Philosopher's Stone',
'author': 'J. K. Rowling',
'read': False
},
{
'title': 'Green Eggs and Ham',
'author': 'Dr. Seuss',
'read': True
}
]
在后端程序app.py文件中,添加访问路由:
代码语言:javascript复制@app.route('/books', methods=['GET'])
def all_books():
return jsonify({
'status': 'success',
'books': BOOKS
})
运行flask服务,在浏览器中访问http://127.0.0.1:5000/books接口,将看到:
代码语言:javascript复制{
"books": [
{
"author": "Jack Kerouac",
"read": true,
"title": "On the Road"
},
{
"author": "J. K. Rowling",
"read": false,
"title": "Harry Potter and the Philosopher's Stone"
},
{
"author": "Dr. Seuss",
"read": true,
"title": "Green Eggs and Ham"
}
],
"status": "success"
}
更新Books.vue组件:
代码语言:javascript复制<template>
<div class="container">
<div class="row">
<div class="col-sm-10">
<h1>Books</h1>
<hr><br><br>
<button type="button" class="btn btn-success btn-sm">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>
<button type="button" class="btn btn-warning btn-sm">Update</button>
<button type="button" class="btn btn-danger btn-sm">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
books: [],
};
},
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);
});
},
},
created() {
this.getBooks();
},
};
</script>
现在运行前端程序:
代码语言:javascript复制$ npm run serve
打开浏览器访问:http://127.0.0.1:8080,你将看到:
接下来,我们将使用一个模态组件来添加一本新书。我们将在前端程序中安装Bootstrap Vue库,它提供了一组使用基于Bootstrap的HTML和CSS样式设计的Vue组件。
首先安装bootstrap-vue库:
代码语言:javascript复制$ npm install bootstrap-vue@2.0.0-rc.11 --save
在client/src/main.js中添加Bootstrap Vue库:
代码语言:javascript复制import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import 'bootstrap/dist/css/bootstrap.css'
import BootstrapVue from 'bootstrap-vue';
Vue.config.productionTip = false
Vue.use(BootstrapVue);
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
添加一个POST请求的接口服务
在app.py文件中,增加一个POST请求,用来完成添加一个本书的功能:
代码语言:javascript复制@app.route('/books', methods=['GET', 'POST'])
def all_books():
response_object = {'status': 'success'}
if request.method == 'POST':
post_data = request.get_json()
BOOKS.append({
'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)
更新imports:
代码语言:javascript复制from flask import Flask, jsonify, request
更新前端程序中Books.vue文件,最终应该是下面这样:
代码语言:javascript复制<template>
<div class="container">
<div class="row">
<div class="col-sm-10">
<h1>Books</h1>
<hr><br><br>
<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>
<button type="button" class="btn btn-warning btn-sm">Update</button>
<button type="button" class="btn btn-danger btn-sm">Delete</button>
</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 type="submit" variant="primary">Submit</b-button>
<b-button type="reset" variant="danger">Reset</b-button>
</b-form>
</b-modal>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
books: [],
addBookForm: {
title: '',
author: '',
read: [],
},
};
},
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();
})
.catch((error) => {
// eslint-disable-next-line
console.log(error);
this.getBooks();
});
},
initForm() {
this.addBookForm.title = '';
this.addBookForm.author = '';
this.addBookForm.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();
},
},
created() {
this.getBooks();
},
};
</script>
现在运行前后端程序,让我们添加一本书试试。点击’add book’按钮,将看到:
接下来,让我们添加一个提示组件,以便在添加新书之后向最终用户显示一条消息。我们将为此创建一个新的组件,因为您可能会在许多组件中使用该功能。
添加一个名为Alert.vue的新文件,在”client/src/components”目录下:
代码语言:javascript复制<template>
<p>It works!</p>
</template>
然后把Alert组件添加到Books组件的JavaScript脚本部分添加该组件:
代码语言:javascript复制<script>
import axios from 'axios';
import Alert from './Alert';
...
export default {
data() {
return {
books: [],
addBookForm: {
title: '',
author: '',
read: [],
},
};
},
components: {
alert: Alert,
},
...
};
</script>
然后,我们就可以在template部分引入组件,就正常使用了。
代码语言:javascript复制<template>
<b-container>
<b-row>
<b-col col sm="10">
<h1>Books</h1>
<hr><br><br>
<alert></alert>
<button type="button" class="btn btn-success btn-sm" v-b-modal.book-modal>Add Book</button>
...
</b-col>
</b-row>
</b-container>
</template>
现在刷新浏览器,你将看到:
现在重写Alert.vue组件,具体内容:
代码语言:javascript复制<template>
<div>
<b-alert variant="success" show>{{ message }}</b-alert>
<br>
</div>
</template>
<script>
export default {
props: ['message'],
};
</script>
然后在Books.vue组件中,重写一下alert组件,具体内容:
代码语言:javascript复制<alert message="hi"></alert>
现在刷新一下浏览器,看看效果吧。不出错的话,应该是下面这样的。
添加的提醒组件,是添加书籍成功后,给出提示。但是目前是一直显示在页面上的。所有我们需要再处理一下。
首先,在Books.vue组件的data中,添加两个数据分别为message、showMessage。具体如下:
代码语言:javascript复制data() {
return {
books: [],
addBookForm: {
title: '',
author: '',
read: [],
},
message: '',
showMessage: false,
};
},
然后,在Books.vue组件的addBook方法中,控制message的内容和是否显示。具体如下:
代码语言:javascript复制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();
});
},
最后,需要在引用的alert组件上,加上v-if控制组件是显示。具体如下:
代码语言:javascript复制<alert :message=message v-if="showMessage"></alert>
现在可以去刷新浏览器,添加一本新书,看看效果。未完待续,明天继续分享更新和删除书籍两个功能。
如果觉得内容还不错,分享给更多朋友,一起提升编程技能。