Vue + Flask 实现单页面应用

发条地精
• 阅读 262

今天使用我们一起来尝试,使用 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 文件夹,这里就是我们写前端代码的地方了

Vue + Flask 实现单页面应用

如下文件的作用

  • 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

说明我们的前端代码构建成功。

现在我们在浏览器中打开上面的地址,就可以得到页面如下:

Vue + Flask 实现单页面应用

后端

后端代码,我准备用 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,可以查看其官网。

至此,一个简单的前后端分离的单页面应用就完成了。

看完本文,你可以按着步骤自己实现下。刚接触的伙伴在看的过程中在某些地方可能有疑惑,其实我也研究了好久,也有好多存疑的地方。不过,我还是建议不要妄求每个点都了解的特别清楚,先明白关键点,试着实现一下,回头去看相关资料的时候,也更有感触一些。

以上就是本次分享的所有内容,如果你觉得文章还不错,欢迎关注公众号:Python编程学习圈,每日干货分享,发送“J”还可领取大量学习资料。或是前往编程学习网,了解更多编程技术知识。

点赞
收藏
评论区
推荐文章
九旬 九旬
4年前
前端培训-Vue专题之Vue基础
简介特点:MVVM框架,双向绑定,数据驱动,单页面,组件化。区别Vue和jQuery的区别:不直接操作DOM,而是操作数据。案例:HelloWorld你好,世界HTML代码:xml<h1msg</h1jQuery实现javascript$("h1").text("你好,世界");Vue实现javascriptthis.msg'你好,世界'
Python进阶者 Python进阶者
4年前
Vue的学习笔记(下篇)
一、什么是Vue.js?Vue是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue也完全能够为复杂的单页应用提供驱动。前面几天我们已经分享了和,今天我们一起来看看下篇。二
20pzqm 20pzqm
3年前
vue+electron 环境搭建记录(基于vue-cli-plugin-electron-builder)
目标搭建vueelectron的工程主要步骤构建初始化工程创建vue3工程使用vuecli工具创建一个vue3工程vueui使用网页创建,注意vue版本选3.0,构建工具选择yarn:::tip选择yarn工具::::::tip手动选择依赖::::::tip开启vuexvueroutereslintless等功能
明月 明月
3年前
vue常见面试题
1.有使用过vue吗?说说你对vue的理解?2.说说你对SPA单页面的理解,它的优缺点分别是什么?如何实现SPA应用呢?3.什么是双向绑定?原理是什么?4.请描述下你对vue生命周期的理解?在created和mounted这两个生命周期中请求数据有什么区别呢?5.Vue组件之间的通信方式都有哪些?6.vshow和vif有什么区别?使用场景分别是什
Easter79 Easter79
3年前
springboot+vue 登录页面(一)
首先了解的技术点是:后台:springboot,mybatis,mybatis逆向工程,mysql,日志前端:nodejs,npm,cnpm,vue,vuecli,webpack,elementui,router,axios开发工具:idea,webstorm该项目前端使用的是vue,目的是实现前后端分离后台:1.选择spr
徐小夕 徐小夕
4年前
一张图教你快速玩转vue-cli3
前言本文系统的梳理了vuecli3搭建项目的常见用法,目的在于让你快速掌握独立搭建vue项目的能力。你将会了解如下知识点:如何安装项目插件添加浏览器支持如何配置scss/stylus共享全局变量如何整合elementUI等第三方框架并实现按需引入配置单/多页面如何配置自定义环境变量如何在vue.config.js定制自己的we
Python进阶者 Python进阶者
4年前
Vue的学习笔记(中篇)
一、什么是Vue.js?Vue是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue也完全能够为复杂的单页应用提供驱动。上篇文章我们讲述了基础,可以戳这里:。这篇文章我
Stella981 Stella981
3年前
Nuxt.js是什么,为什么使用它、Nuxt.js环境搭建
1\.Nuxt.js概述1.1我们一起做过的SPASPA(singlepagewebapplication)单页Web应用,Web不再是一张张页面,而是一个整体的应用,一个由路由系统、数据系统、页面(组件)系统 等等,组成的应用程序。Vue就是SPA
linbojue linbojue
1年前
Vue3+Nuxt3打造SSR网站应用,0到1实现服务端渲染
Vue3Nuxt3打造SSR网站应用,0到1实现服务端渲染download》shanxueit.com/364/项目介绍项目名称:基于Vue3ViteTS的elementplus业务组件二次封装一、项目背景和目标随着前端技术的不断发展,Vue3、Vi
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(