Vue + Flask 实现单页面应用
Posted 萝卜大杂烩
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue + Flask 实现单页面应用相关的知识,希望对你有一定的参考价值。
今天使用我们一起来尝试,使用 Vue + Flask 搭建一个简单的单页面应用。
前端
环境配置
首先安装 vue
1npm install vue
创建 vue 工程
1# 使用 webpack 打包工具初始化一个名为 frontend 的工程
2vue init webpack frontend
安装依赖
1# 进入工程目录
2cd frontend
3# 安装 vue-router
4npm install vue-router --save-dev
5# 安装 element-ui
6npm i element-ui -S
7# 安装 SASS 加载器
8npm install sass-loader node-sass --save-dev
9# 安装依赖
10npm install
启动工程
1npm run dev
此时,一个最简 vue 应用就完成了。
我们看一下 src 文件夹,这里就是我们写前端代码的地方了
如下文件的作用
assets:用于存放资源文件
components:用于存放 Vue 功能组件
views:用于存放 Vue 视图组件
router:用于存放 vue-router 配置
api:存放编写的 api 调用代码
config:用于存放一些公共配置,如后端 url 等
utils:公共方法
App.vue:组件模板
main.js:项目的入口文件
下面我们就简单实现一个登陆功能,来进一步理解下各个文件的作用。
添加代码
首先处理配置信息,在 config 文件夹中创建 url.js 文件
1const devUrl = 'http://127.0.0.1:9980';
2//const proUrl = 'http://apiUrl.com';
3
4export default{
5 apiUrl: devUrl,
6 apiPrefix: 'api',
7 gitHub: ''
8}
在 api 文件夹中创建 https.js 文件
1import axios from 'axios'
2import qs from 'qs'
3import Config from '../config';
4
5axios.defaults.timeout = 5000;
6axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
7axios.defaults.baseURL = '';
8
9function buildApiUrl(url) {
10 return `${Config.apiUrl}/${Config.apiPrefix}/${url}`;
11}
12
13axios.interceptors.request.use((config) => {
14 if(config.method == 'post'){
15 config.data = qs.stringify(config.data);
16 }
17 return config;
18}, (error) => {
19 console.log('error params')
20 return Promise.reject(error);
21}
22);
23
24axios.interceptors.response.use((res) => {
25 if(!res.data.success) {
26 return Promise.resolve(res);
27 }
28 return res;
29}, (error) => {
30 console.log('Network error')
31 return Promise.reject(error);
32}
33);
34
35//返回一个Promise(发送post请求)
36export function fetchPost(url, params) {
37 let apiUrl = buildApiUrl(url);
38 return new Promise((resolve, reject) => {
39 axios.post(apiUrl, params)
40 .then(response => {
41 resolve(response);
42 }, err => {
43 reject(err);
44 })
45 .catch((error) => {
46 reject(error)
47 })
48 })
49}
50////返回一个Promise(发送get请求)
51export function fetchGet(url, param) {
52 let apiUrl = buildApiUrl(url);
53 return new Promise((resolve, reject) => {
54 axios.get(apiUrl, {params: param})
55 .then(response => {
56 resolve(response)
57 }, err => {
58 reject(err)
59 })
60 .catch((error) => {
61 reject(error)
62 })
63 })
64}
65
66export default {
67 fetchGet,
68 fetchPost
69}
这里封装了 axios 的 post 和 get 请求。
在 views 下面创建首页视图 Main.vue
1<template>
2 <div>
3 首页
4 </div>
5</template>
6
7<script>
8 export default{
9 name: "Main"
10 }
11</script>
12
13<style>
14</style>
在 views 下面创建登陆视图 Login.vue
1<template>
2 <div>
3 <el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box">
4 <h3 class="login-title">欢迎登录</h3>
5 <el-form-item label="账号" prop="username">
6 <el-input type="text" placeholder="请输入账号" v-model="form.username"/>
7 </el-form-item>
8 <el-form-item label="密码" prop="password">
9 <el-input type="password" placeholder="请输入密码" v-model="form.password"/>
10 </el-form-item>
11 <el-form-item>
12 <el-button class="login-button" type="primary" v-on:click="onSubmit('loginForm')">登录</el-button>
13 </el-form-item>
14 </el-form>
15
16 <el-dialog
17 title="温馨提示"
18 :visible.sync="dialogVisible"
19 width="30%"
20 :before-close="handleClose">
21 <span>请输入账号和密码</span>
22 <span slot="footer" class="dialog-footer">
23 <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
24 </span>
25 </el-dialog>
26
27 <el-dialog
28 title="温馨提示"
29 :visible.sync="dialogVisible1"
30 width="30%"
31 :before-close="handleClose">
32 <span>错误的账号或密码</span>
33 <span slot="footer" class="dialog-footer">
34 <el-button type="primary" @click="dialogVisible1 = false">确 定</el-button>
35 </span>
36 </el-dialog>
37 </div>
38</template>
39
40<script>
41import https from '../api/https.js'
42 export default {
43 name: "Login",
44 data() {
45 return {
46 form: {
47 username: '',
48 password: ''
49 },
50
51 // 表单验证,需要在 el-form-item 元素中增加 prop 属性
52 rules: {
53 username: [
54 {required: true, message: '账号不可为空', trigger: 'blur'}
55 ],
56 password: [
57 {required: true, message: '密码不可为空', trigger: 'blur'}
58 ]
59 },
60
61 // 对话框显示和隐藏
62 dialogVisible: false,
63 dialogVisible1: false,
64 }
65 },
66 methods: {
67 onSubmit(formName) {
68 // 为表单绑定验证功能
69 this.$refs[formName].validate((valid) => {
70 var username = this.form['username'];
71 var pwd = this.form['password'];
72 var login_info = {username: username, password: pwd};
73
74 if (valid) {
75 https.fetchPost('login', login_info).then((data) => {
76 console.log(data.data['code'])
77 if (data.data['code'] == 200) {
78 this.$router.push("/home");
79 } else {
80 this.dialogVisible1 = true;
81 return false;
82 }
83 })
84 // 使用 vue-router 路由到指定页面,该方式称之为编程式导航
85 //this.$router.push("/main");
86 } else {
87 this.dialogVisible = true;
88 return false;
89 }
90 });
91 },
92 handleClose() {
93
94 }
95 }
96 }
97</script>
98
99<style lang="scss" scoped>
100 .login-button {
101 text-align: center;
102 }
103 .login-box {
104 border: 1px solid #DCDFE6;
105 width: 350px;
106 margin: 180px auto;
107 padding: 35px 35px 15px 35px;
108 border-radius: 5px;
109 -webkit-border-radius: 5px;
110 -moz-border-radius: 5px;
111 box-shadow: 0 0 25px #909399;
112 }
113
114 .login-title {
115 text-align: center;
116 margin: 0 auto 40px auto;
117 color: #303133;
118 }
119</style>
修改 router 下面路由函数 index.js
1import Vue from 'vue'
2import Router from 'vue-router'
3import HelloWorld from '@/components/HelloWorld'
4import Login from '@/views/Login'
5import Main from '@/views/Main'
6
7Vue.use(Router)
8
9export default new Router({
10 routes: [
11 {
12 path: '/',
13 name: 'HelloWorld',
14 component: HelloWorld
15 },
16 {
17 // Main 页面
18 path: '/main',
19 name: 'Main',
20 component: Main
21 },
22 {
23 // 登陆页面
24 path: '/login',
25 name: 'Login',
26 component: Login
27 },
28 ]
29})
修改 App.vue 文件
1<template>
2 <div id="app">
3 <!--<img src="./assets/logo.png">-->
4 <router-view/>
5 </div>
6</template>
7
8<script>
9export default {
10 name: 'App'
11}
12</script>
13
14<style>
15#app {
16 font-family: 'Avenir', Helvetica, Arial, sans-serif;
17 -webkit-font-smoothing: antialiased;
18 -moz-osx-font-smoothing: grayscale;
19 text-align: center;
20 color: #2c3e50;
21 margin-top: 60px;
22}
23</style>
最后在配置入口文件 main.js
1// The Vue build version to load with the `import` command
2// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3import Vue from 'vue'
4import App from './App'
5import router from './router'
6import VueRouter from 'vue-router'
7
8// 导入 elementUI
9import ElementUI from 'element-ui'
10import 'element-ui/lib/theme-chalk/index.css'
11
12// 导入 axios
13import axios from 'axios'
14import QS from 'qs'
15
16Vue.prototype.$axios = axios
17Vue.prototype.qs = QS
18
19Vue.config.productionTip = false
20
21Vue.use(VueRouter)
22Vue.use(ElementUI)
23
24
25/* eslint-disable no-new */
26new Vue({
27 el: '#app',
28 router,
29 //components: { App },
30 //template: '<App/>'
31 render: h => h(App)
32
33})
下面我们启动我们的前端程序
1npm run dev
如果看到类似的
1Your application is running here: http://localhost:8080
后端
后端代码,我准备用 flask + flask_restful 来搭建
1class LoginView(Resource):
2 def post(self):
3 try:
4 username = request.get_json()['username']
5 pwd = request.get_json()['password']
6 user = User.query.filter_by(username=username).first()
7 if user is not None and user.verify_password(pwd):
8 login_user(user)
9 return {'code': 200, 'message': 'you are login now!'}
10 else:
11 return {'code': 403, 'message': 'wrong account or password'}
12 except:
13 raise
14
15
16api_login.add_resource(LoginView, '/login')
这里仅仅给出了最核心的 api 代码,还是非常简单的。更多的关于 flask_restful,可以查看其官网。
至此,一个简单的前后端分离的单页面应用就完成了。
看完本文,你可以按着步骤自己实现下。刚接触的伙伴在看的过程中在某些地方可能有疑惑,其实我也研究了好久,也有好多存疑的地方。不过,我还是建议不要妄求每个点都了解的特别清楚,先明白关键点,试着实现一下,回头去看相关资料的时候,也更有感触一些。
猜泥稀饭:
以上是关于Vue + Flask 实现单页面应用的主要内容,如果未能解决你的问题,请参考以下文章