vue3+element-plus+登录逻辑token+环境搭建
vue3+element-plus+登录逻辑token环境搭建
安装脚手架工具
1 npm i @vue/cli@4.5.13 -g
验证是否安装成功
1 vue -V # 输出 @vue/cli 4.5.13
脚手架初始化目录结构
1 vue create jd-shop-manager

手动配置需要的功能






进入到项目目录
1 cd jd-shop-manager
附加其他依赖
1 npm i axios element-plus pinia -S
运行项目
1 npm run serve
浏览器输入localhost:8080查看效果

配置第三方库,main.js根目录
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// 1. 引入 { createPinia }
import { createPinia } from 'pinia'
import router from './router'
createApp(App)
// 2. 安装插件
.use(createPinia())
.use(ElementPlus)
.use(router)
.mount('#app')
创建文件utils/request.js,关于token认证,
- 获取token
- 保存token
- 后续携带toke
import Axios from 'axios';
const req = Axios.create({
// baseURL:'http://localhost:3000' // 跨域
baseURL:'/api' // 实例独特的表示,走代理解决跨域
});
// 拦截器 = 公共行为: 请求loading 响应关闭loading
// 响应的错误常规处理 401 => 无权访问, 路由跳转到401页面
// 请求时 如果有token, 自动添加到请求头,响应时自动存储token
req.interceptors.response.use((response)=>{
// response:{ data,config:{ headers } }
if (response.data.token) {
// 保存到本地存储: sessionStorage, localStorage
sessionStorage.setItem('token',response.data.token)
}
// 处理响应的业务异常
return response;
},(err)=>{
// 4xx 5xx异常
// 非业务范畴的通用异常提示
console.log('响应异常:',err)
})
// 请求使用token
req.interceptors.request.use((config)=>{
const token = sessionStorage.getItem('token');
if (token) {
config.headers.token = token;
}
return config;
});
export default req;
Axios,vue.config.js配置代理,去玩微博里面找
创建文件api/user.js
1
// 引入3000端口的实例
import req from '@/utils/request';
export const test = ()=> {
return req.get('/')
}
export const login = (data)=>{
return req({
url:'/login',
method:'post',
data
})
}
export const loadMenu = ()=>{
return req.get('/menus/build')
}
pinia插件配置,创建文件store/user.js
// 3. 定义一个Store
// 3.1 引入定义Store的函数
import { defineStore } from 'pinia';
// 4.按约定俗成 返回useXxx
export const useUser = defineStore({
id:'user',
state(){
return {
userInfo:{},
userMenu:[]
}
},
// 修改方式
actions:{
setUserInfo(user){
this.userInfo = user;
},
// { userMenu:值 }
setUserMenu(patchData) {
this.$patch(patchData);
}
}
})
配置路由文件
创建router/index.js
import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '../views/Home.vue'
import { useUser } from '@/store/user'
import { loadMenu } from '@/api/user';
import Layout from '@/views/Layout.vue'
function checkLogin() {
// 前端验证token有效性
// 请求后端验证token有效性
return window.sessionStorage.getItem('token');
}
function asyncRouteHandler(routes) {
return routes.map(route=>{
// 判断Componet是不是一个布局组件名 Layout
if (route.component === 'Layout') {
route.component = Layout;
} else {
const compPath = route.component;
route.component = () => import(`../views/${compPath}.vue`)
}
// 处理children
if (route.children && route.children.length > 0) {
route.children = asyncRouteHandler(route.children);
}
// 返回route
return route;
});
}
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
},
{
path: '/login',
name: 'Login',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/Login.vue')
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
async function loadAsyncMenu(to, next) {
const user = useUser();
// 动态根据用户的角色或者id拿到他能看到的页面,并生成路由
const res = await loadMenu();
console.log(res.data,'路由数据'); // []
const asyncRoutes = asyncRouteHandler(res.data);
// Todo: 保存菜单到pinia
user.setUserMenu({ userMenu:res.data });
// 添加到原来的路由对象中
asyncRoutes.forEach(r=>{
router.addRoute(r);
});
// 重新进入路由 , replace避免多一个上一步
next({...to,replace:true});
}
// 路由守卫, 在每次确认路由和跳转页面之前
router.beforeEach((to, from, next) => {
const user = useUser();
// next(); 放行
// next(route对象|| stringPath ); 重定向
// next(false); 取消用户导航行为
// 不调用 白屏卡住
// to 代表当前的访问路径 from 代表从哪里来 to|from.path 具体路径
// 访问白名单(可以是个数组)不需要验证 /login
if (to.path === '/login' || to.path === '/register') {
// 不验证/不重定向 => 放行
return next();
}
// 需要验证
if (!checkLogin()) {
// 去登录
// return next('/login?redirect='+ to.path);
return next({
name: 'Login', query: {
redirect: to.path
}
});
}
// 登录了, 判断是否已生成路由
if (user.userMenu && user.userMenu.length > 0) {
return next(); // 放行
}
// 没有菜单,加载菜单
loadAsyncMenu(to, next)
})
export default router
实现一个基于ElementPlus的基础登录框
创建Login.vue中写
<template>
<el-form label-width="80px" ref="formRef" :model="form" :rules="rules">
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="form.password"></el-input>
</el-form-item>
<el-form-item>
<el-button @click="submit(formRef)">提交</el-button>
<el-button @click="reset(formRef)">重置</el-button>
</el-form-item>
</el-form>
</template>
<script setup>
//基本 内部多属性
import { ref, reactive } from 'vue';
import { test, login } from '@/api/user'
import { useUser } from '@/store/user';
import { useRoute,useRouter } from 'vue-router'
// 一定要在方法内使用 useUser
const user = useUser(); // 相当于setup方法
const route = useRoute();
const router = useRouter();
// 单向数据输出,双向数据绑定,还需要API方法的调用
const formSize = ref('default'); // formSize.value
const ruleForm = reactive({ // 直接跟原始结构一样 ruleForm.username
username: 'Hello123',
password: '123456'
})
// 需要改变的复杂对象, reactive, 性能优化,直接使用固定对象
const rules = {
username: [
{ required: true, message: '必须输入用户名', trigger: 'blur' },
],
password: [
{ required: true, message: '必须输入密码', trigger: 'blur' },
]
}
// 获取页面组件对象
const ruleFormRef = ref();
// const doSubmit = () => {
// // 需要注意
// ruleFormRef.value.validate((valid, fields) => {
// if (valid) {
// console.log('submit!')
// } else {
// console.log('error submit!', fields)
// }
// })
// }
// 传递参数的方式
const doSubmit = (form) => {
// 需要注意
form.validate(async (valid, fields) => {
if (valid) {
console.log('submit!');
// login
let res = await login(ruleForm);
console.log(res, '测试数据');
// 登录成功
// 修改Pinia里面的数据状态
// user.setUserInfo({
// username: 'Green'
// });
// 跳转到首页 或者 [之前地址栏的页面] 路由参数redirect
router.push(route.query.redirect || '/');
} else {
console.log('error submit!', fields)
}
})
}
样式篇
- 初始化样式

html,body { height: 100%; width: 100%;}a { text-decoration: none; }ul {padding:0; }li {list-style: none; }html,body,h1,h2,h3,h4,h5,h6 { padding:0; margin:0; }span {display:inline-block; }
vue3+element-plus+登录逻辑token+环境搭建的更多相关文章
- 【Vue3+Express实战】项目开发环境搭建
大家好,我是半夏,一个刚刚开始写文的沙雕程序员.如果喜欢我的文章,可以关注 点赞 加我微信:frontendpicker,一起学习交流前端,成为更优秀的工程师-关注公众号:搞前端的半夏,了解更多前端知 ...
- [精华][推荐]CAS SSO 单点登录框架学习 环境搭建
1.了解单点登录 SSO 主要特点是: SSO 应用之间使用 Web 协议(如 HTTPS) ,并且只有一个登录入口. SSO 的体系中有下面三种角色: 1) User(多个) 2) Web 应用( ...
- ssh运行环境搭建及测试
一.运行环境 1.Spring环境 Spring是一站式开发框架,在SSH中主要有以下作用,就像一个大管家: 控制反转(Inversion of Control):类不再自己进行类创建,而是交给Spr ...
- web 单一平台登录逻辑
单点登录逻辑token=cookie('login_token');serverToken=get(token);if(serverToken!='注销'){ set('userid_已登录token ...
- ASP.NET WebAPI 双向token实现对接小程序登录逻辑
最近在学习用asp.net webapi搭建小程序的后台服务,因为基于小程序端和后台二者的通信,不像OAuth(开放授权),存在第三方应用.所以这个token是双向的,一个是对用户的,一个是对接口的. ...
- Shrio00 Shiro认证登录、权限管理环境搭建
基础环境准备: JDK -> java version "1.8.0_101" MAVEN -> Apache Maven 3.5.0 1 导入依赖 mysql驱动 m ...
- Windows 环境搭建 PostgreSQL 逻辑复制高可用架构数据库服务
本文主要介绍 Windows 环境下搭建 PostgreSQL 的主从逻辑复制,关于 PostgreSQl 的相关运维文章,网络上大多都是 Linux 环境下的操作,鲜有在 Windows 环境下配置 ...
- Struts2开发环境搭建,及一个简单登录功能实例
首先是搭建Struts2环境. 第一步 下载Struts2去Struts官网 http://struts.apache.org/ 下载Struts2组件.截至目前,struts2最新版本为2.3.1. ...
- 1、IOS开发--iPad之仿制QQ空间(登录界面搭建+登录逻辑实现)
开始搭建登录界面 登录界面效果图: 相关的图片资源下载百度云备份链接: http://pan.baidu.com/s/1o71cvMU 密码: 2h7e 步骤开始: 设置辅助窗口的位置在下方 快捷键o ...
随机推荐
- Java Stream 函数式接口外部实例的引用
Java Function Interface 函数式接口: Stream.empty() .filter(Predicate) .map(Function) .forEach(Consumer); ...
- Java基础——01
今日学习 2020-2-27 Java多态 多态性格式 /* 代码中体现多态性 其实就是一句话:父类指向子类对象 格式: 父类名称 对象名= new 子类名称(): 或者 接口名称 对象名 = new ...
- KingbaseES 如何实现Oracle pipelined 功能
管道函数即是可以返回行集合(可以使嵌套表nested table 或数组 varray)的函数,我们可以像查询物理表一样查询它或者将其赋值给集合变量.KingbaseES 数据库可以用 setof 实 ...
- 【读书笔记】C#高级编程 第二章 核心C#
(一)第一个C#程序 创建一个控制台应用程序,然后输入代码,输入完毕后点击F5 Console.WriteLine();这条语句的意思:把括号内的内容输出到界面上: Console.ReadKey() ...
- flink-cdc同步mysql数据到kafka
本文首发于我的个人博客网站 等待下一个秋-Flink 什么是CDC? CDC是(Change Data Capture 变更数据获取)的简称.核心思想是,监测并捕获数据库的变动(包括数据 或 数据表的 ...
- Python数据科学手册-Pandas:合并数据集
将不同的数据源进行合并 , 类似数据库 join merge . 工具函数 concat / append pd.concat() 简易合并 合并高维数据 默认按行合并. axis=0 ,试试 axi ...
- [MRCTF2020]Ez_bypass WP
首先打开页面 他提示说f12里面有东西,于是直接ctrl+u 查看源代码 I put something in F12 for you include 'flag.php'; $flag='MRCTF ...
- 依赖项安全检测新利器:Scorecard API
Scorecard 是 OpenSSF 旗下的开源项目,用于评估开源软件风险,本文由该项目的主要贡献者 Naveen 撰写. 现代软件是建立在数百个甚至数千个第三方开源组件之上的,这些通常被称为依赖项 ...
- day03-3私聊功能
多用户即时通讯系统03 4.编码实现02 4.4功能实现-私聊功能实现 4.4.1思路分析 客户端 - 发送者: 用户在控制台输入信息,客户端接收内容 将消息构建成Messgae对象,通过对应的soc ...
- 基于 Apache Hudi + Presto + AWS S3 构建开放Lakehouse
认识Lakehouse 数据仓库被认为是对结构化数据执行分析的标准,但它不能处理非结构化数据. 包括诸如文本.图像.音频.视频和其他格式的信息. 此外机器学习和人工智能在业务的各个方面变得越来越普遍, ...