紧接上一篇 Flask 和 Vue.js 开发及整合部署实例,来体验一下它们与 Bootstrap/BootstrapVue 的集成。漂亮的网站少不得一个好的 CSS 框架,现在有许许多的 CSS 框架可选,纯 CSS 的, 轻量级的, 含 JS 的 CSS 框架,如 Pure, Bulma, Spectre, 国产的 Element 等。而我总觉得 Bootstrap 更是五臟俱全,像 Element 专为 Vue.js 打造的一样,Bootstrap 也有 BootstrpVue 那样一个结晶品。
本文准确的内容应该是关于 Vue.js 与 Bootstrap/BootstrapVue 的话题,与 Flask 没什么事,不过这里呢,还是强拉上 Flask, 由 Flask 的 API 来产生一些数据。
同样是阅读 Flask和Vue.js构建全栈单页面web应用【通过Flask开发RESTful API】的一个实践品。本篇基于 Flask 和 Vue.js 开发及整合部署实例 中的步骤建立的项目 flask-vue-app,方便起见,用了一个新项目名称 flask-vue-bootstrap。记得我们为 Flask 和 Vue.js 分别建立了 backend 和 frontend 两个子项目。
安装体验 Bootstrap
在 frontend 目录中执行
$ npm install bootstrap --save # 当前(2020-07-04) 安装版本为 bootstrap@4.5.0,锁定版本安装用 npm instll bootstrap@4.5.0 --save
注:忽略 jquery 和 proper.js 的警告,不要安装它们
把 Bootstrap 样式导入到 frontend 项目中,只需要在 frontend/src/main.js 中加上一行
1 |
import 'bootstrap/dist/css/bootstrap.css'; |
可以想像这一步就完成了 Bootstrap 的 css 和 js 文件的导入,相当于下面两行代码
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
接下来要应用 Bootstrap 的样子,先在 frontend/src/App.vue 的 style 部分中的 #app
块中加上
1 |
margin-top: 60px; |
这样才不至于下面要显示的按钮紧贴着页面顶部,然后在 ping 组件 frontend/components/Ping.vue 中的 <template> 部分修改为
1 2 3 4 5 |
<template> <div class="container"> <button type="button" class="btn btn-primary">{{ msg }}</button> </div> </template> |
样式 container
, btn
, 和 btn-primary
就是来自于 Bootstrap
这时候假如 backend
和 frontend
下还分别运行着
$ python app.py # backend 目录下
$ npm run serve # frontend 目录下
上边两个服务没运行的话就执行它们,这时候 http://localhost:8080/ping 会自动刷新,显示了 Bootstrap 风格的 pong!
按钮
显示一个 Bootstrap 表格
再来一个例子,做一个显示 Book 列表的页面,Bootstrap 风格,数据由 Flask API 提供。也借些了解一下 Vue.js 的简要开发步骤,完整的 CRUD 程序的开发还要再放一放
创建一个 Books 组件
需要创建文件 frontend/components/Books.vue 文件,内容为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
<template> <div class="container"> <div class="row"> <div class="col-sm-12"> <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> <div class="btn-group" role="group"> <button type="button" class="btn btn-warning btn-sm">Update</button> <button type="button" class="btn btn-danger btn-sm">Delete</button> </div> </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/api/books'; axios.get(path) .then((res) => { this.books = res.data.books; }) .catch((error) => { // eslint-disable-next-line console.error(error); }); }, }, created() { this.getBooks(); }, }; </script> |
由以上内容可知,该组件将从 http://localhost:5000/api/books API 获取数据,数据的结构为 [{title: '...', author: '...', read: true/false}, ...]
Vue 的 /
路由指向 Books 组件
更新 fontend/router/index 文件,两处改动
首先引入 Books 组件
1 |
import Books from './components/Books.vue' |
再在 const routes
数组中把 path: '/' 的路由更改为
1 2 3 4 5 |
{ path: '/', name: 'Books', component: Books, } |
用 http://localhost:8080/ 将能访问 Books 列表。要显示出 Books 列表还需要在 Flask 中创建一个 /api/books
API
创建 Flask API /api/books
在 backend/app.py 中添加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
BOOKS = [ { 'title': 'Software Telemetry', 'author': 'Jamie Riedesel', 'read': True }, { 'title': 'Grokking Streaming Systems', 'author': 'Josh Fischer and Ning Wang', 'read': False }, { 'title': 'Rust in Action', 'author': 'Tim McNamara', 'read': True } ] @app.route('/api/books', methods=['GET']) def all_books(): return jsonify({ 'status': 'success', 'books': BOOKS }) |
我们在 Manning 出版社找了畅销书的前三本,/api/books
返回 JSON 字符串.
打开 http://localhost:8080/, 看到
关于 BootstrapVue
有了 Bootstrap 为什么还要 BootstrapVue 呢?记得前面安装 Bootstrap 时提示有些组件依赖到 jQuery, 而 Vue 使用的是虚拟 DOM, 如果使用 jQuery 来操作 DOM,将无法实现 Vue 的 View 与 Model 的双向绑定。BootstrapVue 解除了 Bootstrap 对 jQuery 的依赖问题,同时 BootstrapVue 还为 Vue 提供了很多标签指令,如 b 开头的 <b-button> 等。
注意:千万不要用 jQuery 去直接操作绑定了 Vue 数据的 DOM 元素。
安装 BootstrapVue, 在 frontend 目录中执行
$ npm install bootstrap-vue --save # 当前(2020-07-04) 安装的 BootstrapVue 是 2.15.0,所以欲锁定安装版本可用 npm install bootstrap-vue@2.15.0 --save
BootstrapVue 的使用,修改 frontend/src/main.js, 其加加上两行
1 2 3 4 |
import BootstrapVue from 'bootstrap-vue'; import 'bootstrap-vue/dist/bootstrap-vue.css'; // 不加上这行,显示 BootstrapVue 组件时样式不对,如 b-modal 背景黑色不透明 Vue.use(BootstrapVue); |
Vue 组件中应用 BootstrapVue 的实例,可以在 frontend/src/components/Books.vue 中把行
1 |
<button type="button" class="btn btn-success btn-sm">Add Book</Button> |
改为
1 |
<b-button class="btn-success btn-sm">Add Book</b-button> |
在浏览器中,以上 <b-button> 的写法分别会被渲染为
1 |
<button type="button" class="btn btn-success btn-sm btn-secondary">Add Book</button> |
BootstrapVue 还支持许多的 HTML 组件,特别是在用到 Modal 窗口时应该要用 BootstrapVue 的 <b-modal> 标签,因为 Bootstrap 的 Modal 组件要使用到 jQuery,在 Vue 项目应尽力避免使用 jQuery 来操作 DOM.
再试 Flask 与 Vue.js 的集成
这是一个回顾,具体集成实现的原理见上一篇 Flask 和 Vue.js 开发及整合部署实例。假如现在在项目的根目录,下面命令用于集成 Flask 与 Vue.js,完后只需要启动 Flask
1 2 3 4 5 |
$ cd frontend $ npm run build $ cd ../backend $ ln -s ../frontend/dist static $ python app.py |
不需要启动 npm run serve
了,直接通过 Flask 的服务访问 http://localhost:5000
这能获得与之前访问 http://localhost:8080 一样的效果。
小结
本文的全部关键操作总结如下,其他都是 Vue 的常规操作了:
npm install bootstrap --save
- src/main.js 中加
import 'bootstrap/dist/css/bootstrap.css;
npm install bootstrap-vue --save
- src/main.js 中再加
import BootstrapVue from 'bootstrap-vue;
,import 'bootstrap-vue/dist/bootstrap-vue.css;
和Vue.use(BootstrapVue)
嗯,有了这篇,基本上就解决了使用PYTHON进行WEB前后端开发的问题了。