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认证,

  1. 获取token
  2. 保存token
  3. 后续携带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+环境搭建的更多相关文章

  1. 【Vue3+Express实战】项目开发环境搭建

    大家好,我是半夏,一个刚刚开始写文的沙雕程序员.如果喜欢我的文章,可以关注 点赞 加我微信:frontendpicker,一起学习交流前端,成为更优秀的工程师-关注公众号:搞前端的半夏,了解更多前端知 ...

  2. [精华][推荐]CAS SSO 单点登录框架学习 环境搭建

    1.了解单点登录  SSO 主要特点是: SSO 应用之间使用 Web 协议(如 HTTPS) ,并且只有一个登录入口. SSO 的体系中有下面三种角色: 1) User(多个) 2) Web 应用( ...

  3. ssh运行环境搭建及测试

    一.运行环境 1.Spring环境 Spring是一站式开发框架,在SSH中主要有以下作用,就像一个大管家: 控制反转(Inversion of Control):类不再自己进行类创建,而是交给Spr ...

  4. web 单一平台登录逻辑

    单点登录逻辑token=cookie('login_token');serverToken=get(token);if(serverToken!='注销'){ set('userid_已登录token ...

  5. ASP.NET WebAPI 双向token实现对接小程序登录逻辑

    最近在学习用asp.net webapi搭建小程序的后台服务,因为基于小程序端和后台二者的通信,不像OAuth(开放授权),存在第三方应用.所以这个token是双向的,一个是对用户的,一个是对接口的. ...

  6. Shrio00 Shiro认证登录、权限管理环境搭建

    基础环境准备: JDK -> java version "1.8.0_101" MAVEN -> Apache Maven 3.5.0 1 导入依赖 mysql驱动 m ...

  7. Windows 环境搭建 PostgreSQL 逻辑复制高可用架构数据库服务

    本文主要介绍 Windows 环境下搭建 PostgreSQL 的主从逻辑复制,关于 PostgreSQl 的相关运维文章,网络上大多都是 Linux 环境下的操作,鲜有在 Windows 环境下配置 ...

  8. Struts2开发环境搭建,及一个简单登录功能实例

    首先是搭建Struts2环境. 第一步 下载Struts2去Struts官网 http://struts.apache.org/ 下载Struts2组件.截至目前,struts2最新版本为2.3.1. ...

  9. 1、IOS开发--iPad之仿制QQ空间(登录界面搭建+登录逻辑实现)

    开始搭建登录界面 登录界面效果图: 相关的图片资源下载百度云备份链接: http://pan.baidu.com/s/1o71cvMU 密码: 2h7e 步骤开始: 设置辅助窗口的位置在下方 快捷键o ...

随机推荐

  1. SP6779 GSS7 - Can you answer these queries VII(线段树,树链剖分)

    水题,只是坑点多,\(tag\)为\(0\)时可能也要\(pushdown\),所以要\(bool\)标记是否需要.最后树链剖分询问时注意线段有向!!! #include <cstring> ...

  2. nmtui 字符界面图形模式配置

    一.通过nmtui配置网络参数 Linux系统配置网络参数的方式有很多种,其中最简单最直接的方式就是直接修改网卡配置文件,但这种方式也很容易出错,比如说IPADDR.NETMASK.GATEWAY等参 ...

  3. spring boot 中英文官方文档

    中文文档:http://oopsguy.com/documents/springboot-docs/1.5.4/index.html#boot-features 英文官方文档:https://docs ...

  4. 漏洞扫描工具awvs13破解

    AWVS13_windows破解版:链接:https://pan.baidu.com/s/1qeGiNubhWgY6oeMx_IkMtg 提取码:2i2o AWVS13_linux破解版:链接:htt ...

  5. redis-hash命令

    一.HDEL key field [field ...] 从 key 指定的哈希集中移除指定的域.在哈希集中不存在的域将被忽略. 如果 key 指定的哈希集不存在,它将被认为是一个空的哈希集,该命令将 ...

  6. 弹簧高跷题解---双向DP---DD(XYX)​​​​​​​的博客

    三 . 弹簧高跷 时间限制: 1 Sec  内存限制: 128 MB 题目描述.输入.输出          ----------- 方法 这道题用DP是可以解决的.因为每一次跳跃都与前一次跳跃有关, ...

  7. k8s-Pod调度

    Deployment全自动调度 NodeSelector定向调度 NodeAffinity亲和性 PodAffinity-Pod亲和性与互斥性 污点和容忍度 DaemonSet Job CronJob ...

  8. Go语言知识查漏补缺|基本数据类型

    前言 学习Go半年之后,我决定重新开始阅读<The Go Programing Language>,对书中涉及重点进行全面讲解,这是Go语言知识查漏补缺系列的文章第二篇,前一篇文章则对应书 ...

  9. flutter系列之:移动端的手势基础GestureDetector

    目录 简介 Pointers和Listener GestureDetector 手势冲突 总结 简介 移动的和PC端有什么不同呢?同样的H5可以运行在APP端,也可以运行在PC端.两者最大的区别就是移 ...

  10. 项目实践2:使用html和CSS实现图片轮播

    好家伙, 使用html和CSS实现简单的图片切换(轮播图) 来自:(7条消息) 使用CSS实现简单的图片切换(轮播图)_LexingtonCV16的博客-CSDN博客_css实现图片切换 1.首先创建 ...