一 组件表单的数据绑定
给el-form 加上:model属性,进行数据绑定(form对象)
给每一个表单项: input 输入框 v-model 属性绑定到【数据对象】中的【具体属性】中
![](https://i-blog.csdnimg.cn/blog_migrate/ad88a688784bc22cef2c0c299c7c0c20.png)
1.2 给密码弄成密文
![](https://i-blog.csdnimg.cn/blog_migrate/8874c173e5bd77522e9649c7b6871770.png)
二 element ui表单验证
![](https://i-blog.csdnimg.cn/blog_migrate/cb7fcf8b0d0f53e60841ad16a559f1cc.png)
1.1 给form表单绑定一个 :rules= "rules "
el-form 通过rules属性指定一个校验对象
![](https://i-blog.csdnimg.cn/blog_migrate/f511ebeb5d13df2031650c1ac2a31f48.png)
1.2 在data数据中添加 规则
在data当中定义这个校验对象,其中每一个属性就是一个校验规则
![](https://i-blog.csdnimg.cn/blog_migrate/375345f22be72fb6789be5dc159ad696.png)
1.3 给item项指定prop属性, 等于一个具体的规则
希望使用这一个验证规则,去验证这个表单输入项
为不同的表单item项,通过prop去指定校验规则,来进行表单的验证
![](https://i-blog.csdnimg.cn/blog_migrate/abeab01dc8ef8fa639f3e44adadc4130.png)
总结:
校验分为三个步骤:
1 el-form 通过rules属性指定一个校验对象
2 在data当中定义这个校验对象,其中每一个属性就是一个校验规则(多个校验对象)
3 为不同的表单item项,通过prop去指定校验规则,来进行表单的验证
2.1 编写代码
![](https://i-blog.csdnimg.cn/blog_migrate/840c29eea9c1c01c7ab253fb445b76cf.png)
![](https://i-blog.csdnimg.cn/blog_migrate/602ca5b9c387e575069fcb37c12d1db7.png)
三表单的重置
![](https://i-blog.csdnimg.cn/blog_migrate/ca483e075880e4e6c2d58cd64fd54ac9.png)
【拿到这个表单的实例对象】, 然后调用restfelds函数,就可以重置表单
如何拿到这个表单的实例对象那?
给组件加一个ref的引用。 这个引用对象就是这个实例对象
![](https://i-blog.csdnimg.cn/blog_migrate/da899b928deb7b6d6d7b095b59338f7e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6dfd1041c12987d2732c93eb05d9095f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7ce572ae51df1337620cfbeaf0709c59.png)
编写代码:
![](https://i-blog.csdnimg.cn/blog_migrate/64ba3a27b87901096f4ae6c333f1c9c7.png)
四 登录之前的预验证
![](https://i-blog.csdnimg.cn/blog_migrate/5ee1920723b935671ea730c32c722f8d.png)
登录之前需要进行预验证
![](https://i-blog.csdnimg.cn/blog_migrate/c7c0f9d2fd27cfd89e6ccb8d7c84476f.png)
只需要拿到实例对象的引用对象,就可以直接调用validate函数
![](https://i-blog.csdnimg.cn/blog_migrate/1efef30529b344486b9ffaa436669527.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2a871eda0a419588819d9b1f500db2f0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/aea9f2da7663ef6f6cb2f3c5f46dd798.png)
编写代码:
![](https://i-blog.csdnimg.cn/blog_migrate/402bc8aec312125fa9aab14053b41c2a.png)
五 根据预验证是否发起请求
5.1 配置axios
![](https://i-blog.csdnimg.cn/blog_migrate/59fc150ddbd875edfc517f27a9b3e8d2.png)
5.2 调用接口分析
![](https://i-blog.csdnimg.cn/blog_migrate/e49c60b4ea887ea99aecdc8963d722fe.png)
await. async简化promise 方法,async 放在最近的函数上
login没有/
![](https://i-blog.csdnimg.cn/blog_migrate/ecb1d42c94e1f48fe18e65c49bd50103.png)
其中 data才是服务器返回的真实数据
所以解构赋值一下,获取真实的接口数据
![](https://i-blog.csdnimg.cn/blog_migrate/98a753bad484e21b45b6742d7eea71f2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3714d1b5301801bce86f1b058b9295fd.png)
注意报错:if(!valid) return; 这样写不对, if(!valid) return false
访问地址:http://vue-shop-api-t.itheima.net/api/private/v1
有可能报跨域的问题
![](https://i-blog.csdnimg.cn/blog_migrate/824419b6ee7662abd0478ba633c2d36f.png)
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
// devServer: {
// // 代理配置
// proxy: {
// // 这里的api 表示如果我们的请求地址有/api的时候,就出触发代理机制
// // localhost:8888/api/abc => 代理给另一个服务器
// // 本地的前端 =》 本地的后端 =》 代理我们向另一个服务器发请求 (行得通)
// // 本地的前端 =》 另外一个服务器发请求 (跨域 行不通)
// '/api': {
// target: 'http://vue-shop-api-t.itheima.net', // 我们要代理的地址
// changeOrigin: true, // 是否跨域 需要设置此值为true 才可以让本地服务代理我们发出请求
// // 路径重写
// pathRewrite: {
// // 重新路由 localhost:8888/api/login => www.baidu.com/api/login
// '^/api': '' // 假设我们想把 localhost:8888/api/login 变成www.baidu.com/login 就需要这么做 '^/api': '' 的意思是吧/api幻化成’’
// }
// }
// }
// }
})
5.3代码
![](https://i-blog.csdnimg.cn/blog_migrate/2bbcde4f9250f2c1e1275ff7b9325697.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2b23d6501d1d7e54639ce8e3b139166b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/82b71df7a3418634e72611a67cef923d.png)
注意:
if (res.meta.status !== 200) {
![](https://i-blog.csdnimg.cn/blog_migrate/481e9415a0ad52c30da00dc410415ef6.png)
报错: 拿不到数据,res有数据,但是res.data 打印是undefined
![](https://i-blog.csdnimg.cn/blog_migrate/bbdbb70dcecd110f36152b67b6fd0634.png)
原因是没有写await 注意await 和async的位置
添加await即可
![](https://i-blog.csdnimg.cn/blog_migrate/c77eeaa5e7ce0dec0c04bd2636620d1e.png)
六登录组件配置弹框提示
![](https://i-blog.csdnimg.cn/blog_migrate/2b8098d77c0191260586e4232ac1a874.png)
6.1 导入组件
message 组件和别的有点不一样,需要全局挂载
把这个组件挂载到了vue原型对象上,这样每一个组件都可以通过this 来访问到$message
![](https://i-blog.csdnimg.cn/blog_migrate/e7a059a391b16815f7c42edef3bbee2e.png)
6.2使用
![](https://i-blog.csdnimg.cn/blog_migrate/5e107ce9817379fc120ab3bd97d664bd.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5a29971d17dcdd96fad55b938196873a.png)
6.3 加载的图标使用:
![](https://i-blog.csdnimg.cn/blog_migrate/05de018e9e93805405bf03e4cab03028.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a727f4a574fed9eef44a76a3d39ec619.png)
<el-button
type="primary"
@click="login"
:loading="loading"
class="login"
>登录</el-button
>
loading: false,
login () {
this.loading = true
this.$refs.formRef.validate(async valid => {
if (!valid) {
this.loading = false
return false
}
const { data: res } = await this.$http.post('login', this.form)
console.log(res)
if (res.meta.status !== 200) {
this.loading = false
return this.$message.error('登录失败')
}
this.$message.success('登录成功')
this.loading = false
})
}
也可以给整个区域添加loading, 在最外的大盒子添加v-loading="loading"
还是使用同一个变量, 来控制区域,和按钮的加载
七登录组件登录成功之后的行为
1. 将登录成功之后的 token,保存到客户端的 sessionStorage(会话机制/只在当前页面生效)中 localStorage(持久话机制/关闭页面也不会忘记数据)
1.1 项目中除了登录之外的API接口,必须在登录之后才能访问
1.2 token 只应在当前网站打开期间生效, 所以将 token 保存在 sessionStorage中
2. 通过编程式路由导航跳转到后台主页,路由地址是 /home
tooken 为什么不保存到localstorage,而是保存到sessionStorage 当中那?
localstorage 是持久化机制,sessionStorage 是会话期间的存储机制。token 只应在当前网站打开期间生效, 所以将 token 保存在 sessionStorage中
7.1代码:
![](https://i-blog.csdnimg.cn/blog_migrate/112ed73338baa33a1265ef2cf8c0d8a2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9f8d36a34f044a059c059f27b050c141.png)
报错:
![](https://i-blog.csdnimg.cn/blog_migrate/65133e9910889184561ab8a8750933f0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5f5ddd8a89f0a5057249b895b929aff3.png)
自己没引入message这个组件
7.2 添加home组件
![](https://i-blog.csdnimg.cn/blog_migrate/074bb2af0d38b91f4028478f14e9e326.png)
![](https://i-blog.csdnimg.cn/blog_migrate/122d837c912e44d5ef5129285dde8c12.png)
八路由导航守卫控制访问权限
登录状态可以看到home页面, 未登录状态不能看到home页面
![](https://i-blog.csdnimg.cn/blog_migrate/bfed34c7b381500d1e2f4223e4bf59c7.png)
8.1 改造代码
![](https://i-blog.csdnimg.cn/blog_migrate/fac05c398abb4704990d013a6235e768.png)
改造:
![](https://i-blog.csdnimg.cn/blog_migrate/a878c8831414704cb476b9998b62e108.png)
如果使登录页, 登录页不需要要权限控制,直接放行。 (不执行下边的代码了)!!!!
如果没有被return出去, 就说明用户访问的不是登录页。而是一个有权限的页面。
既然有权限了,就先拿到token,根据是否有token来决定是否强制跳转
如果没有token,强制跳转到login页面,如果有token,则放行
import Vue from 'vue'
import VueRouter from 'vue-router'
const Login = () =>
import(/* webpackChunkName: "login_home_welome" */ 'components/login/Login')
const Home = () =>
import(/* webpackChunkName: "login_home_welome" */ 'components/home/Home')
const Welcome = () =>
import(
/* webpackChunkName: "login_home_welome" */ 'components/home/welcome/Welcome'
)
const Users = () =>
import(
/* webpackChunkName: "Users_Rights_Roles" */ 'components/home/users/Users'
)
const Rights = () =>
import(
/* webpackChunkName: "Users_Rights_Roles" */ 'components/home/power/rights/Rights'
)
const Roles = () =>
import(
/* webpackChunkName: "Users_Rights_Roles" */ 'components/home/power/roles/Roles'
)
const Cate = () =>
import(
/* webpackChunkName: "Cate_Params" */ 'components/home/goods/cate/Cate'
)
const Params = () =>
import(
/* webpackChunkName: "Cate_Params" */ 'components/home/goods/params/Params'
)
const GoodsList = () =>
import(
/* webpackChunkName: "GoodsList_Add" */ 'components/home/goods/list/List'
)
const Add = () =>
import(
/* webpackChunkName: "GoodsList_Add" */ 'components/home/goods/list/children/Add'
)
const Order = () =>
import(/* webpackChunkName: "Order_Report" */ 'components/home/order/Order')
const Report = () =>
import(/* webpackChunkName: "Order_Report" */ 'components/home/report/Report')
Vue.use(VueRouter)
const routes = [
{
path: '/',
redirect: '/login'
},
{
path: '/login',
component: Login
},
{
path: '/home',
component: Home,
redirect: '/welcome',
children: [
{
path: '/welcome',
component: Welcome
},
{
path: '/users',
component: Users
},
{
path: '/rights',
component: Rights
},
{
path: '/roles',
component: Roles
},
{
path: '/categories',
component: Cate
},
{
path: '/params',
component: Params
},
{
path: '/goods',
component: GoodsList
},
{
path: '/goods/add',
component: Add
},
{
path: '/orders',
component: Order
},
{
path: '/reports',
component: Report
}
]
}
]
const router = new VueRouter({
routes
})
router.beforeEach((to, from, next) => {
// to 将访问哪一个路径
// from 代表从哪个路径跳转而来
// next 是一个函数,表示放行
// next() 放行 next('/login') 强制跳转
if (to.path === '/login') return next()
// 获取token
const token = window.sessionStorage.getItem('token')
if (!token) return next('/login')
next()
})
export default router
九 退出
![](https://i-blog.csdnimg.cn/blog_migrate/b7c249cad337cb40ce9cd8fc01973aaf.png)
![](https://i-blog.csdnimg.cn/blog_migrate/67c2854820694ff550518664368ec713.png)
十:优化elementUi组件的导入形式
![](https://i-blog.csdnimg.cn/blog_migrate/a838b716324fa2ca2c8cdb027f34f17d.png)
优化:
![](https://i-blog.csdnimg.cn/blog_migrate/0bf38b22d749755a77be85025b828f02.png)
十一:提交登录功能代码
1 提交本地代码
![](https://i-blog.csdnimg.cn/blog_migrate/65acf45275854d016582fa3083ce7635.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9760a74e7bc4b78763bcee814d6e92fa.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2d08e3c9098d4798e50f46f25cdedf4c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/8a1ac56eeda0c3057874b5a3132f0cce.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9fbade09539731f9f2440a9f6d7029bb.png)
2 把login分支 的代码合并到master分支:
1 切换到master
![](https://i-blog.csdnimg.cn/blog_migrate/56e0a5c34a874c61f8a746812f8d20c9.png)
2 mergin
![](https://i-blog.csdnimg.cn/blog_migrate/260adc2a1f8bfc3139404239578e7ac2.png)
3 本地代码提交到远端
![](https://i-blog.csdnimg.cn/blog_migrate/b2e1593005d4230be6d22c8fed1577d3.png)
查看是否成功:
![](https://i-blog.csdnimg.cn/blog_migrate/6ac7ec414c85fea5e9c67943b962d6b2.png)
4 把本地login分支推送到远端
![](https://i-blog.csdnimg.cn/blog_migrate/15be2dc6f29005701b12e8a63f9247f1.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f957da08fd1141db360c26fabf140c55.png)
此时远程就多了一个分支
![](https://i-blog.csdnimg.cn/blog_migrate/53c3339fa3cbe773112dcf7cce8281b1.png)