效果

image.png
跳转到登录页
image.png

2-1 store里添加logout action

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

image.png
src/store/modules/user.ts

  1. import { Module, MutationTree, ActionTree } from 'vuex'
  2. import { IRootState } from '@/store'
  3. import { login } from '@/api/user'
  4. import { setToken, removeToken } from '@/utils/auth'
  5. // login params
  6. export interface IUserInfo {
  7. username: string;
  8. password: string;
  9. }
  10. // 定义state类型
  11. export interface IUserState {
  12. token: string;
  13. }
  14. // mutations类型
  15. type IMutations = MutationTree<IUserState>
  16. // actions类型
  17. type IActions = ActionTree<IUserState, IRootState>
  18. // 定义state
  19. const state: IUserState = {
  20. token: ''
  21. }
  22. // 定义mutation
  23. const mutations: IMutations = {
  24. SET_TOKEN(state, token: string) {
  25. state.token = token
  26. }
  27. }
  28. // 定义action
  29. const actions: IActions = {
  30. login({ commit }, userInfo: IUserInfo) {
  31. const { username, password } = userInfo
  32. return new Promise((resolve, reject) => {
  33. login({ username: username.trim(), password }).then(response => {
  34. const { data } = response
  35. console.log('data', data)
  36. commit('SET_TOKEN', data.token)
  37. setToken(data.token) // localStorage中保存token
  38. resolve(data)
  39. }).catch(error => {
  40. reject(error)
  41. })
  42. })
  43. },
  44. logout({ commit, dispatch }) {
  45. // 退出登录接口我这里就不写了
  46. return new Promise<void>((resolve) => {
  47. // 清空store里token
  48. commit('SET_TOKEN', '')
  49. // 清空localStorage里的token
  50. removeToken()
  51. // 清除所有tag views 派发的是全局action 需要 root: true
  52. dispatch('tagsView/delAllViews', null, { root: true })
  53. resolve()
  54. })
  55. }
  56. }
  57. // 定义user module
  58. const user: Module<IUserState, IRootState> = {
  59. namespaced: true,
  60. state,
  61. mutations,
  62. actions
  63. }
  64. export default user

派发全局action文档

2-2 退出登录

image.png
src/layout/components/avatar/index.vue

  1. <template>
  2. <el-dropdown
  3. class="avatar-container">
  4. <div class="avatar-wrapper">
  5. <img :src="avatar" class="user-avatar">
  6. <i class="el-icon-caret-bottom" />
  7. </div>
  8. <template #dropdown>
  9. <el-dropdown-menu>
  10. <router-link to="/">
  11. <el-dropdown-item>首页</el-dropdown-item>
  12. </router-link>
  13. <router-link to="/profile/index">
  14. <el-dropdown-item>个人设置</el-dropdown-item>
  15. </router-link>
  16. <el-dropdown-item divided @click="logout">
  17. <span style="display: block">退出登录</span>
  18. </el-dropdown-item>
  19. </el-dropdown-menu>
  20. </template>
  21. </el-dropdown>
  22. </template>
  23. <script lang="ts">
  24. import avatar from '@/assets/logo.png'
  25. import { defineComponent, getCurrentInstance } from 'vue'
  26. import { useStore } from '@/store'
  27. export default defineComponent({
  28. setup() {
  29. const store = useStore()
  30. const { proxy } = getCurrentInstance()!
  31. const logout = () => {
  32. store.dispatch('user/logout').then(() => {
  33. proxy?.$message.success('退出登录')
  34. window.location.reload()
  35. })
  36. }
  37. return {
  38. logout,
  39. avatar
  40. }
  41. }
  42. })
  43. </script>
  44. <style lang="scss" scoped>
  45. .avatar-container {
  46. margin-right: 30px;
  47. .avatar-wrapper {
  48. margin-top: 5px;
  49. .user-avatar {
  50. width: 40px;
  51. height: 40px;
  52. border-radius: 10px;
  53. cursor: pointer;
  54. }
  55. .el-icon-caret-bottom {
  56. cursor: pointer;
  57. font-size: 12px;
  58. }
  59. }
  60. }
  61. </style>

登录成功加了个提示
image.png

本节参考源码

https://gitee.com/brolly/vue3-element-admin/commit/9bc1a8f83c299d2bb1c7884b03f077bfde930592