效果
2-1 store里添加logout action
退出登录时 调用user/logout action 清空store token tags view 刷新跳转到登录页 这里退出登录接口我就不写了

src/store/modules/user.ts
import { Module, MutationTree, ActionTree } from 'vuex'import { IRootState } from '@/store'import { login } from '@/api/user'import { setToken, removeToken } from '@/utils/auth'// login paramsexport interface IUserInfo {username: string;password: string;}// 定义state类型export interface IUserState {token: string;}// mutations类型type IMutations = MutationTree<IUserState>// actions类型type IActions = ActionTree<IUserState, IRootState>// 定义stateconst state: IUserState = {token: ''}// 定义mutationconst mutations: IMutations = {SET_TOKEN(state, token: string) {state.token = token}}// 定义actionconst actions: IActions = {login({ commit }, userInfo: IUserInfo) {const { username, password } = userInforeturn new Promise((resolve, reject) => {login({ username: username.trim(), password }).then(response => {const { data } = responseconsole.log('data', data)commit('SET_TOKEN', data.token)setToken(data.token) // localStorage中保存tokenresolve(data)}).catch(error => {reject(error)})})},logout({ commit, dispatch }) {// 退出登录接口我这里就不写了return new Promise<void>((resolve) => {// 清空store里tokencommit('SET_TOKEN', '')// 清空localStorage里的tokenremoveToken()// 清除所有tag views 派发的是全局action 需要 root: truedispatch('tagsView/delAllViews', null, { root: true })resolve()})}}// 定义user moduleconst user: Module<IUserState, IRootState> = {namespaced: true,state,mutations,actions}export default user
2-2 退出登录

src/layout/components/avatar/index.vue
<template><el-dropdownclass="avatar-container"><div class="avatar-wrapper"><img :src="avatar" class="user-avatar"><i class="el-icon-caret-bottom" /></div><template #dropdown><el-dropdown-menu><router-link to="/"><el-dropdown-item>首页</el-dropdown-item></router-link><router-link to="/profile/index"><el-dropdown-item>个人设置</el-dropdown-item></router-link><el-dropdown-item divided @click="logout"><span style="display: block">退出登录</span></el-dropdown-item></el-dropdown-menu></template></el-dropdown></template><script lang="ts">import avatar from '@/assets/logo.png'import { defineComponent, getCurrentInstance } from 'vue'import { useStore } from '@/store'export default defineComponent({setup() {const store = useStore()const { proxy } = getCurrentInstance()!const logout = () => {store.dispatch('user/logout').then(() => {proxy?.$message.success('退出登录')window.location.reload()})}return {logout,avatar}}})</script><style lang="scss" scoped>.avatar-container {margin-right: 30px;.avatar-wrapper {margin-top: 5px;.user-avatar {width: 40px;height: 40px;border-radius: 10px;cursor: pointer;}.el-icon-caret-bottom {cursor: pointer;font-size: 12px;}}}</style>
本节参考源码
https://gitee.com/brolly/vue3-element-admin/commit/9bc1a8f83c299d2bb1c7884b03f077bfde930592

