一. 效果
1.未登陆之前
2.登录界面
3.登录之后路由跳转
二.需求分析
要求:
- 使用vue-cli搭建 创建项目
- 密码输入框有 两个功能,当用户输入时候如果坚持caps lock处于开启状态。 右侧出现提示 caps lock is on
- 当用户点击右侧的眼睛图标的时候, 可以明文和密文的方式显示密码
- 页面的 组件可以使用 element-ui
5.点击login的时候 如果用户名或密码为空,需要把 对应的输入框变红,并且该输入框下方提示提示 用户名或密码不能为空
- 完成输入后, 需要把数据通过ajax(建议使用fetch或者axios第三方库) 发送出去到服务器端,
后台检测用户名和密码
用户名和密码admin/P@ss1234表示登陆成功, 页面切换为成功页面
如果不是,在当前页面提示用户名和密码错误,
7.切换页面的时候浏览器不可以刷新, 参考vue-router,
8.成功页面需要显示欢迎 username
登陆, 但是用户名不可以是hardcode的。参考vuex.。
三.前端:根据需求分析,一步一步地实现
1.使用vue-cli搭建 创建项目
搭建方式:
(1)首先得安装好vue cli的环境 cnpm install -g @vue/cli
,然后通过vue -V
检查vue版本号
(2)如果想在某个目录下创建新项目,就cd到该目录,或者直接在文件管理器打开改目录,然后在目录的路径输入cmd回车,就可以跳到该路径,输入 vue init webpack myproject
, myproject是项目名。
后面的按需填写:
创建成功了是这样子的
然后cd到项目的目录,输入 cnpm install
发现多了个文件夹
最后输入 cnpm run dev
命令启动项目,启动成功会出现以下画面
在浏览器输入这个网址就能测试了
2.路由切换的实现
首先确保是否有安装路由,没有的就去安装
导入和全局引用
然后就可以使用了
在APP.vue里增加路由
<template>
<div id="app">
<router-link :to="{name:'Home'}">首页</router-link>
<router-link :to="{name:'Login'}">登录</router-link>
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
</style>
接着在router目录下修改index.js
import Vue from 'vue'
import Router from 'vue-router'
import Login from '@/components/Login'
import Home from '../components/Home.vue'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/login',
name: 'Login',
component: Login
}
]
})
当登录成功时的路由切换
3.登录界面的实现
由于需求分析里说可以使用element-ui 实现。
所以就用了,但是不知道为什么,修改不了ele-input的背景颜色,所以在输入框的实现我还是用了原生的input。
其中登陆界面的功能如下:
(1)密码输入框有 两个功能,当用户输入时候如果坚持caps lock处于开启状态。 右侧出现提示 caps lock is on
(2) 当用户点击右侧的眼睛图标的时候, 可以明文和密文的方式显示密码
(3)点击login的时候 如果用户名或密码为空,需要把 对应的输入框变红,并且该输入框下方提示提示用户名或密码不能为空
(4)完成输入后, 需要把数据通过ajax(建议使用fetch或者axios第三方库)发送出去到服务器端,后台检测用户名和密码 ,用户名和密码admin/P@ss1234表示登陆成功, 页面切换为成功页面如果不是,在当前页面提示用户名和密码错误
(5)切换页面的时候浏览器不可以刷新, 参考vue-router
(6)成功页面需要显示欢迎 username
登陆, 但是用户名不可以是hardcode的。参考vuex.
这里就不再多解释了,直接先上代码:
<template>
<div id="login" >
<div class="me-login-box me-login-box-radius">
<h1>Login Form</h1>
<el-form ref="userForm" :model="userForm" :rules="rules" >
<el-form-item prop="account" >
<div class="my-form1">
<img src="../../static/img/user.png" id="user-img">
<input class="my-input" placeholder="用户名" v-model="userForm.account" ref="account"/>
</div>
</el-form-item>
<el-form-item prop="password" >
<div class="my-form1">
<img src="../../static/img/lock.png" id="password-img">
<input class="my-input" placeholder="密码" type="password"
v-model="userForm.password" ref="password" @keyup="onHCapitalize($event)"/>
<img src="../../static/img/eyesclosed.png" id="eyes-img" ref="eyes" @click="show()">
<i v-show="bigChar" class="bigchar">大写锁已打开</i>
</div>
</el-form-item>
<el-form-item size="small" class="me-login-button">
<el-button type="primary" @click.native.prevent="login('userForm')">Login</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
export default {
name: 'Login',
data() {
return {
userForm: {
account: '',
password: ''
},
rules: {
account: [
{required: true, message: '用户名不能为空'}//trigger: 'blur'
],
password: [
{required: true, message: '密码不能为空'},
{min: 6, message: 'password must be at least 6 characters'}
]
},
flag:'false',
bigChar:'false'
}
},
methods: {
login(formName) {
let that = this
this.$refs[formName].validate((valid) => {
if (valid) {
if(this.userForm.account.trim()!=""&&this.userForm.password.trim()!=""){
let params =new URLSearchParams();
params.append('account',this.userForm.account);
params.append('password',this.userForm.password);
this.$axios.post('http://localhost:8888/user/login',params)
.then(function (response) {
console.log(response);
if (response.data==='登录成功'){
// user:that.userForm.account
that.$store.commit('updateUserName',that.userForm.account)
that.$router.push({name:'Home'});
}else if(response.data==='登录失败'){
alert("登录失败,用户名不存在或者密码错误")
}
})
.catch(function (error) {
console.log(error);
});
}
} else {
if(this.userForm.account.trim()===""){
this.$refs.account.style.borderColor="red";
}else{
this.$refs.account.style.borderColor="#797979";
}
if(this.userForm.password.trim()===""){
this.$refs.password.style.borderColor="red";
}else{
this.$refs.password.style.borderColor="#797979";
}
return false;
}
});
},
show(){
if(this.flag){
this.$refs.eyes.src="../../static/img/eyes.png";
this.$refs.password.setAttribute("type", "text");
}else{
this.$refs.eyes.src="../../static/img/eyesclosed.png";
this.$refs.password.setAttribute("type", "password");
}
this.flag=!this.flag;
},
onHCapitalize(event) { // 大写键盘锁打开事件
if(this.firstTochar){
if(event.keyCode===20){
this.bigChar=!this.bigChar;
return;
}
}
//未输入过字母键,或按键不是caps lock,判断每次最后输入的字符的大小写
var e = event||window.event;
var keyvalue = e.keyCode ? e.keyCode : e.which;
var shifKey = e.shiftKey ? e.shiftKey:((keyvalue == 16) ? false : true);//左右Shift
var strlen = this.userForm.password.length;
var password=this.userForm.password;
if(strlen){
var uniCode =password.charCodeAt(strlen-1);
if(keyvalue>=65 && keyvalue<=90){
//如果是字母键
this.firstTochar=true;
if(((uniCode >= 65 && uniCode <= 90) && !shifKey)||((uniCode >= 97 && uniCode <= 122) && shifKey)){
this.bigChar=true;
}else{
this.bigChar=false;
}
}
}
}
}
}
</script>
<style scoped>
#my-form1{
position: relative;
}
#password-img{
width: 25px;
height: 25px;
position: absolute;
margin-top: -12.5px;
top:50%;
left: 5px;
}
#user-img{
width: 20px;
height: 20px;
position: absolute;
margin-top: -10px;
top:50%;
left: 5px;
}
#eyes-img{
width: 20px;
height: 20px;
position: absolute;
margin-top: -10px;
top:50%;
right:10px;
}
#login {
position: absolute;
min-width: 100%;
min-height: 100%;
background-color: #464646;
color: #FFFFFF;
}
.me-login-box {
position: absolute;
width: 300px;
height: 260px;
background-color: #464646;
margin-top: 150px;
margin-left: -180px;
left: 50%;
padding: 30px;
}
.me-login-box-radius {
border-radius: 10px;
}
.me-login-box h1 {
text-align: center;
font-size: 24px;
margin-bottom: 20px;
vertical-align: middle;
}
.me-login-design {
text-align: center;
font-family: 'Open Sans', sans-serif;
font-size: 18px;
}
.me-login-design-color {
color: #5FB878 ;
}
.me-login-button {
text-align: center;
}
.me-login-button button {
width: 100%;
}
.my-input{
width: 255px;
height: 35px;
background: #323232 !important;
color: #FFFFFF;
border: 0.1px solid #797979;
padding-left: 35px;
}
.bigchar{
width: 100px;
height: 30px;
position: absolute;
}
</style>
4.axios的使用过程
1.在项目cmd输入npm install vue-axios --save 安装axios
2.安装成功后,在main.js页面引用
在组件调用
5.vuex使用
科普:什么是vuex?vuex 是一个专门为vue.js应用程序开发的状态管理模式。
vuex中,有默认的五种基本的对象:
state:存储状态(变量)
getters:对数据获取之前的再次编译,可以理解为state的计算属性。我们在组件中使用 s o t r e . g e t t e r s . f u n ( ) m u t a t i o n s : 修 改 状 态 , 并 且 是 同 步 的 。 在 组 件 中 使 用 sotre.getters.fun() mutations:修改状态,并且是同步的。在组件中使用 sotre.getters.fun()mutations:修改状态,并且是同步的。在组件中使用store.commit(’’,params)。这个和我们组件中的自定义事件类似。
actions:异步操作。在组件中使用是$store.dispath(’’)
modules:store的子模块,为了开发大型项目,方便状态管理而使用的。这里我们就不解释了,用起来和上面的一样。
本次的开发只用到了state,mutations。
下载安装vuex
(1) 通过此命令安装 npm install vuex --save
(2)新建如图
引用
在main.js引用
index.js
import Vue from 'vue'
import Vuex from 'vuex'
//挂载Vuex
Vue.use(Vuex)
//创建VueX对象
const store = new Vuex.Store({
state:{
//存放的键值对就是所要管理的状态
name:'这位可爱的游客'
},
mutations: {
updateUserName (state, account) {
state.name = account
}
}
})
export default store
怎么修改state的值呢?
6.element-ui 使用
(1)通过npm i element-ui -S
命令安装element-ui
(2)引用
( 3)调用
四.后端的实现
1.LoginController接口的实现
package com.example.myserver.controller;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping(value = "/user", method = RequestMethod.POST)
public class LoginController {
@GetMapping("/login")
public String login(@RequestParam String account,String password){
if (password.equals("P@ss1234")&&account.equals("admin")){
return "登录成功";
}else{
return "登录失败";
}
}
}
2.解决跨域 WebMVCConfig.java
package com.example.myserver.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMVCConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
//跨域配置
registry.addMapping("/**").allowedOrigins("http://localhost:8086");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
}
}
五.总结
对于vue的使用变得熟练一点了,还是要努力学习呀!加油!奥里给!
所有代码:https://gitee.com/wangjinchan/vue_login