Vue实战系列(一) - 最简化登录页面
1. 创建项目骨架
# 1. 利用Vue-CLI创建项目 vue create vue-login #2. 添加依赖框架 # 进入到项目根目录 cd vue-login # 添加 element,一个 element 风格的 UI 框架 vue add element # 安装 axios,用于网络请求 npm install axios # 安装 Vuex,用于管理状态 npm install vuex --save # 安装 路由,用于实现两个 Vue 页面的跳转 npm install vue-router
2. 创建相应功能的目录结构,进行分层开发
- api (网络请求接口包) - router (路由配置包) - store (Vuex 状态管理包) - utils (工具包) - views (vue 视图包,存放所有 vue 代码,可根据功能模块进行相应分包)
3. 运行项目
npm run serve 在浏览器输入:http://localhost:8080/
4. View 层代码编写
编写三个 vue 文件:
login.vue(登录页面)
success.vue(登录成功页面)
error.vue(登录失败页面)
login.vue
<template> <div> <el-card class="login-form-layout"> <el-form autocomplete="on" :model="loginForm" ref="loginForm" label-position="left" > <div style="text-align: center"> <svg-icon icon-class="login-mall" style="width: 56px;height: 56px;color: #409EFF"></svg-icon> </div> <h2 class="login-title color-main">登录页面</h2> <el-form-item prop="username"> <el-input name="username" type="text" v-model="loginForm.username" autocomplete="on" placeholder="请输入用户名" > <span slot="prefix"> <svg-icon icon-class="user" class="color-main"></svg-icon> </span> </el-input> </el-form-item> <el-form-item prop="password"> <el-input name="password" :type="pwdType" @keyup.enter.native="handleLogin" v-model="loginForm.password" autocomplete="on" placeholder="请输入密码" > <span slot="prefix"> <svg-icon icon-class="password" class="color-main"></svg-icon> </span> <span slot="suffix" @click="showPwd"> <svg-icon icon-class="eye" class="color-main"></svg-icon> </span> </el-input> </el-form-item> <el-form-item style="margin-bottom: 60px"> <el-button style="width: 100%" type="primary" :loading="loading" @click.native.prevent="handleLogin" >登录</el-button> </el-form-item> </el-form> </el-card> </div> </template> <script> export default { name: "login", data() { return { loginForm: { username: "admin", password: "123456" }, loading: false, pwdType: "password", }; }, methods: { showPwd() { if (this.pwdType === "password") { this.pwdType = ""; } else { this.pwdType = "password"; } }, handleLogin() { this.$refs.loginForm.validate(valid => { if (valid) { this.loading = true; this.$store .dispatch("Login", this.loginForm) .then(response => { this.loading = false; let code = response.data.code; if (code == 200) { this.$router.push({ path: "/success", query: { data: response.data.data } }); } else { this.$router.push({ path: "/error", query: { message: response.data.message } }); } }) .catch(() => { this.loading = false; }); } else { // eslint-disable-next-line no-console console.log("参数验证不合法!"); return false; } }); } } }; </script> <style scoped> .login-form-layout { position: absolute; left: 0; right: 0; width: 360px; margin: 140px auto; border-top: 10px solid #409eff; } .login-title { text-align: center; } .login-center-layout { background: #409eff; width: auto; height: auto; max-width: 100%; max-height: 100%; margin-top: 200px; } </style>
success.vue
<template> <div> <h1>Welcome!{{msg}}</h1> </div> </template> <script> export default { data() { return { msg: this.$route.query.data }; }, // data() { //这种方式也可以 // return { // msg: null // }; // }, // created() { // this.msg = this.$route.query.data; // } } </script>
error.vue
<template> <div> <h1>登录错误:{{msg}}</h1> </div> </template> <script> export default { // data() { // return { // msg: this.$route.query.data // }; // }, //使用这种方式也可以显示 msg data() { return { msg: null }; }, created() { this.msg = this.$route.query.message; } };
5. 路由
页面写好了,我们需要依次显示这三个页面,这里我们统一使用路由来管理显示页面。
5-1) 创建路由配置文件
在router 文件夹下创建一个 index.js 文件,内容如下:
import Vue from 'vue' //引入 Vue import VueRouter from 'vue-router' //引入 Vue 路由 Vue.use(VueRouter); //安装插件 export const constantRouterMap = [ //配置默认的路径,默认显示登录页 { path: '/', component: () => import('@/views/login')}, //配置登录成功页面,使用时需要使用 path 路径来实现跳转 { path: '/success', component: () => import('@/views/success')}, //配置登录失败页面,使用时需要使用 path 路径来实现跳转 { path: '/error', component: () => import('@/views/error'), hidden: true } ] export default new VueRouter({ // mode: 'history', //后端支持可开 scrollBehavior: () => ({ y: 0 }), routes: constantRouterMap //指定路由列表
5-2) 将路由添加到程序入口
路由配置文件写好,我们需要把他引入到 main.js 中。
在项目的 src 目录根节点下,找到 main.js。
import Vue from 'vue' import App from './App.vue' import './plugins/element.js' import router from './router' //引入路由配置 Vue.config.productionTip = false new Vue({ render: h => h(App), router, //使用路由配置 }).$mount('#app')
5-3) 配置路由的出入口
现在路由已经完全引入到项目了,但是路由还需要一个出入口,
这个出入口用来告诉路由将路由的内容显示在这里。
修改 App.vue 内容如下:
<template> <div id="app"> <!-- 路由的出入口,路由的内容将被显示在这里 --> <router-view/> </div> </template> <script> export default { name: 'App' } </script>
现在运行程序, 界面如下:
5-4) 路由跳转
this.$router.push({path: "路径"})
在 login.vue 中可以使用 this.$router.push({path: "路径"}) 来跳转到指定路径的路由组件中, 路由跳转核心代码如下: this.$router.push({path: "/success"}); //跳转到成功页 this.$router.push({path: "/error"}); //跳转到失败页
完整代码如下
login.vue
handleLogin() { this.$refs.loginForm.validate(valid => { if (valid) { this.loading = true; this.$store .dispatch("Login", this.loginForm) .then(response => { this.loading = false; let code = response.data.code; if (code == 200) { this.$router.push({ path: "/success", query: { data: response.data.data } }); } else { this.$router.push({ path: "/error", query: { message: response.data.message } }); } }) .catch(() => { this.loading = false; }); } else { // eslint-disable-next-line no-console console.log("参数验证不合法!"); return false; } }); }
6. 使用 Vuex + Axios 方式进行网络请求
6-1) 利用Axios封装请求
axios 是一个网络请求构架,官方推荐使用这种方式进行 http 的请求。
a) 在 utils 包下封装一个请求工具类 request.js
import axios from 'axios' //引入 axios import baseUrl from '../api/baseUrl' //使用环境变量 + 模式的方式定义基础URL // 创建 axios 实例 const service = axios.create({ baseURL: baseUrl, // api 的 base_url timeout: 15000, // 请求超时时间 }) export default service
注: 这里的 baseUrl 涉及 Vue CLI3 的环境变量与模式的概念,见:Vue 环境变量和模式(设置通用baseUrl)
b) 登录请求接口 API
在 api 文件夹下,创建一个登录API文件
login.js
import request from '@/utils/request' //引入封装好的 axios 请求 export function login(username, password) { //登录接口 return request({ //使用封装好的 axios 进行网络请求 url: '/admin/login', method: 'post', data: { //提交的数据 username, password } }) }
6-2) 使用 Vuex 封装 axios
Vuex 是一个状态管理构架。
a)封装 Vuex 中的 module
在 store 文件夹下创建一个 modules 文件夹,然后在此文件夹下创建一个 user.js 文件
import { login } from '@/api/login'//引入登录 api 接口 const user = { actions: { // 登录 Login({ commit }, userInfo) { //定义 Login 方法,在组件中使用 this.$store.dispatch("Login") 调用 const username = userInfo.username.trim() return new Promise((resolve, reject) => { //封装一个 Promise login(username, userInfo.password).then(response => { //使用 login 接口进行网络请求 commit('') //提交一个 mutation,通知状态改变 resolve(response) //将结果封装进 Promise }).catch(error => { reject(error) }) }) }, } } export default user
上面的代码值得解释一下:
1. 引接口 引入 login 接口,之后使用登录接口进行网络请求。 2. 定义action 定义一个 名为 Login 的 action 方法,方便Vue 组件通过 this.$store.dispatch("Login") 调用。 3. 封装Promise Promise,这个类很有意思,官方的解释是“store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise, 并且 store.dispatch 仍旧返回 Promise”。 这话的意思组件中的 dispatch 返回的仍是一个 Promise 类。 因此Promise 中的两个方法 resolve() 与 reject() 分别对应 dispatch 中的 then 与 catch。
b) 创建 Vuex
在 store 文件夹下创建一个 index.js 文件
import Vue from 'vue' //引入 Vue import Vuex from 'vuex' //引入 Vuex import user from './modules/user' //引入 user module Vue.use(Vuex) const store = new Vuex.Store({ modules: { user //使用 user.js 中的 action } }) export default store
c) 将 Vuex 添加到 main.js 文件
修改之前的 main.js 文件如下:
import Vue from 'vue' import App from './App.vue' import './plugins/element.js' import router from './router' //引入路由配置 import store from './store' //引入 Vuex 状态管理 Vue.config.productionTip = false new Vue({ render: h => h(App), router, //使用路由配置 store //使用 Vuex 进行状态管理 }).$mount('#app')
7. 服务端接口
由于这是一篇主要讲Vue的文章, 所以服务端接口这里我就一笔带过了。
可以写一个简易的不带数据库的登录接口(Java)如下:
@RestController public class LoginController { @RequestMapping(value = "/admin/login", method = RequestMethod.POST) public CommonResult login(@RequestBody User user) { if (user.getUsername().equals("admin") && user.getPassword().equals("123456")) return CommonResult.success("admin"); else return CommonResult.validateFailed(); } }
再次访问页面, 效果如下:
登录成功
登录失败
技术改变世界