Vue3+Ts项目——登录页面跳转到首页

前言:根据我上篇所实现的左边菜单栏之后,需要登录成功跳转home页面。主要分为三步。

Vue3+Ts项目——登录页面跳转到首页

      • 第一步:创建三个ts文件结合pinia缓存登录信息和token
        • src\api\userTypes.ts
        • src\stores\modules\user.ts
        • src\stores\counter.ts
      • 第二步:页面调用ts的登录处理方法,router下index.ts路径跳转处理
        • 包含登录操作的vue页面
          • 今天圣诞节,让我来解决上次LoginResponseModel报红问题
        • src\router\index.ts
      • 第三步:检测token过期,登出处理

第一步:创建三个ts文件结合pinia缓存登录信息和token

src\api\userTypes.ts

就是个接口类方便页面和另一个ts文件数据传递,其实也可以不用

export interface LoginResponse {
    userInfo: UserInfo
    token: string
  }

  export interface UserInfo {
    user: string | null
  }
src\stores\modules\user.ts

这个ts就是结合pinia用于处理页面传过来要处理缓存的数据。

import { defineStore } from 'pinia'
import type {LoginResponse, UserInfo} from '@/api/userTypes'

import { useStorage } from '@vueuse/core'

export const useUserStore = defineStore('user', () => {
  const userInfoRef = useStorage('USER_INFO', {} as UserInfo, sessionStorage)
  const tokenRef = useStorage('TOKEN', '', sessionStorage)

  function setUserInfo(userInfo: UserInfo) {
    userInfoRef.value = userInfo
    console.log('userInfoRef====>',userInfoRef);
    
  }
  
  function setToken(token: string) {
    tokenRef.value = token
  }

  function toLogin(param: LoginResponse) {    
    setToken(param.token) 
    setUserInfo(param.userInfo)
  }
  function toLogout() {
    setUserInfo({} as UserInfo);
    setToken("");
    window.location.href = '/login'
}
  function getUsername() {
    return userInfoRef.value.user
  }

  function getToken() {
    return tokenRef.value
  }

  return { toLogin, toLogout, getToken, getUsername }
})
src\stores\counter.ts
import type {App} from 'vue'
import {createPinia} from 'pinia'

const store = createPinia()

export function useStore(app: App<Element>): void {
  app.use(store)
}

export {store}

第二步:页面调用ts的登录处理方法,router下index.ts路径跳转处理

我这边处理是登录接口请求成功之后,再调用toLogin()方法。其实可以结合接口请求一起写,我这个是借鉴Vue + Ts 项目(七)—— 登录页面及登录校验,实现方式很多。我先结合自己项目实现功能。

包含登录操作的vue页面
import { useUserStore } from "@/stores/modules/user";
import { useRouter, useRoute } from "vue-router";
import { LoginResponse } from "@/api/userTypes";
// 引入这三

//再在setup ()下第一行,切记一定要前排。不然router和route为空。 
setup (){
    const userStore = useUserStore();
    const router = useRouter();
    const route = useRoute();
    const LoginResponseModel: Ref<LoginResponse> = ref({
      userInfo: {user:''},
      token: "",
    });

// 再在登录回调成功的地方加上
              LoginResponseModel.userInfo ={
                user:res.user// 根据你自己的数据结构来
              } 
              LoginResponseModel.token = res.token
              userStore.toLogin(LoginResponseModel);
              // 这里LoginResponseModel,会报红。但是不影响流程。我后期看看怎么去红。哈哈哈哈哈,我还是太废了。
              const redirect = route.query.redirect as string
              
              if (redirect) {
                router.replace(redirect)
              } else {
                router.replace('/combination/dashboard')
              }

不前排会报错Cannot read properties of undefined (reading 'replace')
也不要试图用useRouter()直接.replace会报错inject() can only be used inside setup() or functional components.等一些问题

今天圣诞节,让我来解决上次LoginResponseModel报红问题

我感觉当时脑子突然不够用,发现我有点迷,今天好点,需要改动

// userTypes.ts文件
export interface UserInfo {
  user: string | null
  picture: string | null
}
export interface LoginResponse {
    userInfo: UserInfo
    token: string | null
  }

// user.ts文件
  function setToken(token: string|null) {
    tokenRef.value = token
  }

  function toLogin(userInfo: UserInfo , token: string|null) {  
    setToken(token) 
    setUserInfo(userInfo)
  }

// vue调用页面
import type { UserInfo } from "@/api/userTypes";

const userInfo : Ref<UserInfo> = ref({
  user: null,
  picture: null
})

 userInfo.value.user = username
          userInfo.value.picture = picture ? picture : null
          userStore.toLogin(userInfo.value, getToken);
          const redirect = route.query.redirect as string
          //后面跟之前一样
src\router\index.ts

主要是beforeEach方法。

import {createWebHistory, createRouter} from "vue-router";
import type {App} from 'vue'
// 获取所有路由
import routes from './routes'

import { useUserStore } from "@/stores/modules/user";

const router = createRouter({
  routes,
  // 这里使用历史记录模式
  history: createWebHistory()
})

router.beforeEach((to, from, next) => {
  const userStore = useUserStore();  
  const isAuthenticated = userStore.getToken() && userStore.getToken() !== "";
  console.log('====isAuthenticated==',isAuthenticated);
  // isAuthenticated用于判断没有登录缓存,手动属于的路径,不会跳转成功。
  if (isAuthenticated) {
    next();
  } else {
    if (to.name === "login") {
      next();
    } else {
      next({ name: "login", query: { redirect: to.fullPath } });
    }
  }
});

export const useRouter = (app: App<Element>): void => {
    app.use(router)
}

对了,别忘了配置login页面的路由src\router\modules\login.ts,把默认路径也是设置为登录页面

import type { RouteRecord } from '@/router/type'
import BasicLayout from "@/layouts/BasicLayout.vue";
import { CalendarTools } from '@vicons/carbon'  

const loginRoutes: RouteRecord[] = [
  {
    path: "/",
    name:'login',
    meta:{
      hidden: true
    },
    children: [
      {
        path: "/login",
        name: "login",
        component: () => import("@/views/login/login.vue"),
      },
    ],
  },
]

export default loginRoutes

到目前为止,登录成功后已经可以跳转了。先这样

第三步:检测token过期,登出处理

第三步先欠着。下周我再继续学习。毕竟周五了。我心已经起飞了。

今天2023.12.18.周一,天气小雨夹雪。我们继续。
根据我目前项目不需要做过多处理。只需要把token值放headers里

src\stores\modules\apiEncapsulation.ts

import { useUserStore } from "@/stores/modules/user";
import { useRouter } from "vue-router";
import { createDiscreteApi} from "naive-ui"
import { apiToken} from "../../api/apiToken";
import type { DataResult } from "../../api/DataResult ";


const router = useRouter();
const {message} = createDiscreteApi(["message"])


// 接口请求:token过期或未登录,跳转到登录页面
export async function  apiTokenRequest(url: string, method:string){
    const userStore = useUserStore();  
    const isAuthenticated = userStore.getToken() && userStore.getToken() !== "";
    if(isAuthenticated){
        try {// DataResult返回值接口类,可以在userTypes.ts创建再引入使用
        	 // apiToken是 封装的请求方法,引入使用
            await apiToken<DataResult>(url,userStore.getToken(),method )
            .then(function(res){
                if(res.code===0){
                return res
                }else if(res.code===2){
                    router.replace('/')
                    message.error(res.errorMsg)
                }else{
                    message.error(res.errorMsg)
                }
                })
        } catch (error) {
            message.error('Request exception!')
            console.log('error==>',error);
        }
    }else{
      router.replace('/')
      message.warning('未登录,或登录过期')
    }
  }

apiToken方法参考(这里用到的fetch请求)

export function apiToken<T>(url: string, token: string, method:string): Promise<T>{
  return fetch(url,{method: method, headers:{'Authorization' :  "Bearer " + token}})
  .then(response => {
    if (!response.ok) {
      throw new Error(response.statusText)
    }
    return response.json() as Promise<T>
  })
}

Authorization头的主要用作http协议的认证。
Authorization的作用是当客户端访问受口令保护时,服务器端会发送401状态码和WWW-Authenticate响应头,要求客户机使用Authorization来应答。

  config.headers['Authorization'] = 'Bearer ' + getToken()

注意:Bearer 后面需要加一个空格

你可能感兴趣的:(vue.js,前端,typescript)