前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用Flask和Vue.js开发一个单页面应用程序(三)

使用Flask和Vue.js开发一个单页面应用程序(三)

作者头像
TalkPython
发布2019-05-24 16:44:03
1.2K0
发布2019-05-24 16:44:03
举报
文章被收录于专栏:TalkPython

点击蓝字关注△ 回复“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>

现在可以去刷新浏览器,添加一本新书,看看效果。未完待续,明天继续分享更新和删除书籍两个功能。

如果觉得内容还不错,分享给更多朋友,一起提升编程技能。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-03-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 TalkPython 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 添加一个GET请求的接口服务
  • 添加一个POST请求的接口服务
相关产品与服务
Serverless HTTP 服务
Serverless HTTP 服务基于腾讯云 API 网关 和 Web Cloud Function(以下简称“Web Function”)建站云函数(云函数的一种类型)的产品能力,可以支持各种类型的 HTTP 服务开发,实现了 Serverless 与 Web 服务最优雅的结合。用户可以快速构建 Web 原生框架,把本地的 Express、Koa、Nextjs、Nuxtjs 等框架项目快速迁移到云端,同时也支持 Wordpress、Discuz Q 等现有应用模版一键快速创建。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档