对于登陆上的布局需要使用 Element-UI 组件实现布局; 对于登陆功能我们会用到:
然后在项目中,如果想开发一个新功能了,尽量把这个功能放到 git 新的分支上进行开发,当分支功能开发完毕后 再合并到主分支上; 我分支名写为 login, 回车; 会显示创建并切换到 login 分支;
git checkout -b 分支名 // 创建分支
git branch // 查看所有分支
(1)src -> main.js 是入口文件,将 element-ui 引入进去
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
<template>
<div id="app">app 根组件</div>
</template>
<script>
export default {
name: "app",
};
</script>
<style>
</style>
(3)梳理路由文件,进入 router 文件夹,进入 index.js ( 也可以是 router.js )
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
]
const router = new VueRouter({
routes
})
export default router
然后 view 文件夹中的两个文件,About.vue 和 Home.vue 也不再需要了,删除;
还有 components 中的 HelloWorld.vue 也不需要,删除; 现在就是干净的项目文件了;
在组件文件夹 components 中,创建 login.vue,其中有三个区域
<template>
<div>
<!-- 登陆组件 - 模板部分 -->
</div>
</template>
<script>
export default {
// 行为部分
};
</script>
<style lang="less" scoped>
// 样式部分, 需要注意的是 只要是单文件组件, 一定要给 style 标签加上 scope 指令, 放止组件样式冲突
</style>
创建完毕后,找到路由的文件,得通过路由的方式将它渲染到 App.vue,下面是更改后的路由部分,先写好路由规则; 再到 App.vue 的模板中写路由占位符:
import Vue from 'vue';
import VueRouter from 'vue-router';
import Login from '../components/Login.vue';
Vue.use(VueRouter);
const router = new VueRouter({
routes: [
// 写个路由重定向规则, 如果用户访问的是根路径, 就让它自动跳到 /login
{
path: '/', redirect: '/login' },
// 这个意思是当用户访问 path 的路径时, 展示对应的组件
{
path: '/login', component: Login },
],
});
export default router;
<template>
<!-- 路由规则 -->
<router-view></router-view>
</template>
根据上面的步骤,我们已经可以在 Login.vue 组件中写网页登陆的内容了,也会被渲染到 App.vue 中展示;
那么,我们想给登陆界面整一个背景色,我可以在组件三块内容中直接写; 但注意 html 不是占满全屏的,你这样给模板填颜色也就是一条而已; 我们可以到 src -> assets 中添加一个 css 样式表文件夹 -> globle.css,写全局样式;
写完需要到入口文件 main.js 中进行引入才能生效
// 导入全局样式表
import './assets/css/global.css'
然后单独在 global 中写这个页面的样式就行了,根据需求 它现在 html,body 和 #app 应是 100%,差的就是这个元素没 100%,给它也设置 100% ,背景颜色就好了
<template>
<div class="login_container">
登陆组件
</div>
</template>
<script>
export default {
};
</script>
<style lang="less" scoped>
.login_container {
height: 100%;
background-color: #2b4b6b;
}
</style>
登陆框样式就不再解释了,一会儿在 “表单部分” 贴代码:
直接下载的 element-ui 自动下载到 node_modules 里面了,在 main.js 中引入的路径是:
import '../node_modules/element-ui/lib/theme-chalk/index.css';
组件部分用到了 element-ui 中 ”Form 表单“ 部分 这里是链接 ; 选择自己有用的部分拷贝,删掉用不到的属性;
login.vue 组件代码:
<template>
<div class="login_container">
<div class="loginBox">
<!-- 头像区 -->
<div class="avater_box">
<img src="../assets/logo.png" alt="" />
</div>
<!-- 登陆表单区域 -->
<el-form label-width="0px" class="login_form">
<!-- 用户名 -->
<el-form-item>
<el-input></el-input>
</el-form-item>
<!-- 密码 -->
<el-form-item>
<el-input></el-input>
</el-form-item>
<!-- 按钮区域, 去 element-ui 找按钮复制过来-->
<el-form-item class="btns">
<el-button type="primary">登陆</el-button>
<el-button type="">重置</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
export default {
};
</script>
<style lang="less" scoped>
.login_container {
height: 100%;
background-color: #2b4b6b;
}
.loginBox {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 450px;
height: 300px;
background-color: #fff;
border-radius: 10px;
}
.avater_box {
position: absolute;
left: 50%;
transform: translate(-50%, -50%);
width: 100px;
height: 100px;
border: 1px solid #eee;
border-radius: 50%;
padding: 10px;
background: #eee;
box-shadow: 0 0 10px #ddd;
img {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.btns {
display: flex;
justify-content: flex-end;
}
// 文本框得上下布局
.login_form {
position: absolute;
bottom: 0;
width: 100%;
padding: 0 20px;
box-sizing: border-box;
}
</style>
对于文本框前面的图标,可以到 ”input 输入框“ 部分中找 “带 icon 的输入框”,其中两种方式都可以,然后选择在前面或者后面引入图标的代码,看你需求,直接加到 input 中当属性即可; 图标的选择呢,可以到 组件 - “icon 图标” 中找,如果它给的图标没有你想要的,可以借助第三方图标库(比如 “阿里巴巴矢量库”);
引入:
先给你需要的图标下载下来,拿到 fonts 文件夹,这个文件夹应该放到 src 中的 assets
(资源)里面,比较合理,放进去; 然后再来到 main.js 中去引入
// 1. 在 main.js 文件中导入字体图标
import './assets/fonts/iconfont.css'
// 2. 然后在 login.vue 中用类引入
<!-- 用户名 -->
<el-form-item>
<el-input prefix-icon="iconfont icon-yonghu"></el-input>
</el-form-item>
<!-- 密码 -->
<el-form-item>
<el-input prefix-icon="iconfont icon-mima"></el-input>
</el-form-item>
给
最外侧的框中,添加 :model 进行绑定,然后在 script 中,设置 data 进行保存用户名和密码:
// 1. 模板中
<!-- 登陆表单区域 -->
<el-form label-width="0px" class="login_form" :model="loginForm">
<!-- 用户名 -->
<el-form-item>
<el-input prefix-icon="iconfont icon-yonghu" v-model="loginForm.username"></el-input>
</el-form-item>
<!-- 密码 -->
<el-form-item>
<el-input prefix-icon="iconfont icon-mima" v-model="loginForm.password" type:"password"></el-input>
</el-form-item>
// 2. 在 script 标签中
<script>
export default {
data() {
return {
// 这是登陆表单的数据绑定对象
loginForm: {
username: '',
password: ''
}
}
}
};
</script>
目的:当我文本框失去焦点的时候,对表单的内容进行验证
(1)具体实现是通过动态绑定,给最外侧表单标签动态绑定 :rules="loginFormRules"
自定义一个 rules 校验对象名
(2)然后在 data 的 return 中定义 你写自定义的校验对象名字,其中的每一个属性都是一个验证规则,它是一个数组包含对象的形式,每个对象中写不同的验证规则;可以去 element-ui 复制;
(3)怎么让验证规则生效呢,复制这个验证规则名字,到对应标签的父级中定义 prop 属性,将名字当做属性值填进去;
loginFormRules: {
// 验证用户名是否合法
username: [
{
required: true, message: "请输入登陆名称", trigger: "blur" },
{
min: 3,
max: 10,
message: "长度在 3 到 10 个字符",
trigger: "blur",
},
],
// 验证密码是否合法
password: [
{
required: true, message: "请输入登陆密码", trigger: "blur" },
{
min: 6,
max: 15,
message: "长度在 6 到 15 个字符",
trigger: "blur",
},
],
},
在文章 “form” 的最后有个 Form Methods
里面有重置表单的方法,只要我们获取了表单的实例对象,就能直接通过对象访问 resetFields 这个函数,从而重置整个表单; 那么想拿到表单的实例对象,只需要在表单标签中加 ref 的引用,它等于一个引用的名称(自定义),我们只要获得了这个实例对象就能调用 resetFields
函数进行重置;
那我们在重置按钮身上定义个点击事件,事件名为 ”resetLoginForm“,然后再 methods 中进行定义,触发它时(这里到时候回来讲解下!!!!!!)
methods: {
// 点击重置按钮, 重置登陆表单
resetLoginForm() {
// console.log(this); // 获得实例
this.$refs.loginFormRef.resetFields()
},
},
因为我点击重置后,状态框的红色虽然不见了,但是内容是动态绑定的,所以会回到初始状态,也就是我设置的 admin,如果想重置为空,默认动态绑定的值就设置成空字符串就好了;
预验证:我们首先给表单绑定一个点击事件(名起的 login),在调用 login 的时候,先拿到对象的引用,用它去调用 element-ui 给提供的,对整个表单进行校验的方法 validate
,参数为一个回调函数,表单验证成功返回 true,否则返回 false;
如果返回 false,直接 return,如果返回 true,我需要发送请求; 发送请求要用到 axios,到 main.js 去引入; 因为之前已经把 axios 绑定到 Vue 原型链的 $http 属性上了,每一个 Vue 组件都可以通过 this 直接访问到,所以这里直接 this.\$http.get('http://linweiqin.cn:8001/v2/login', this.loginForm)
第一个参数是后端给的登陆接口路径,第二个参数是表单
login() {
// 表单验证合格返回 true, 否则返回 false
this.$refs.loginFormRef.validate(async (valid) => {
if (!valid) return;
// 对于返回的数据我只需要 data, 就把 data 赋值给 res
const {
data: res } = await this.$http.post(
"http://linweiqin.cn:8001/admin/login",
{
user_name: this.loginForm.username,
password: this.loginForm.password,
}
);
console.log(res);
if (res.status !== 1) return this.$message.error("登陆失败");
this.$message.success("登陆成功");
// console.log(res); // 返回值是 promise, 可以用 await, 后期百度查一下解释 valid 前面异步, 不懂
// 其中 data 才是返回的真实数据
});
},
请求成功后,弹框可以到 element UI 中找 “Message 消息提示” - 不同状态,this.$message.error 可以根据你的条件调用成功失败弹窗… (promise 的同步异步不会!!! 研究一下!!!)
将登陆成功之后的 token,保存到 sessionStorage 中;
(1)项目中除了登陆之外的其他 API 接口,必须在登陆之后才能访问;
(2)token 只应在当前网站打开期间生效,所以将 token 保存在 sessionStorage 中