BCVP.VUE3系列第十课:个人中心模块

BCVP 开发者社区出品

BCVP V3开发

数字化

服务化

绿色化

放假不停歇,趁着假期学习下VUE3相关的内容,一方面是自己保持活力,另一方面也是工作需要,本系列是我的自学教程,如果有从0开始学习VUE3的,可以跟着一起练习下,毕竟前端我也是泥腿子出身,这一系列会使用Vite、TS、Pinia、Element-Plus等新知识点,既是查漏补缺,也是知识分享。

代码地址:

https://github.com/anjoy8/bcvp.vue3.git

这是每篇文章一节课一个分支,方便大家学习,会慢慢的将blog.admin项目进行翻新,使用的后端接口还是BlogCore。

系列文章:

第一课:项目初始化与核心知识点说明

第二课:基于泛型基类封装Axios请求

第三课:封装Axios拦截器

第四课:登录页设计

第五课:获取用户信息

第六课:获取动态菜单接口

第七课:基于布局模式实现动态菜单渲染

第八课:丰富面包屑组件

第九课:实现tabs标签栏

0、本文介绍

本文参考的是开源项目

https://gitee.com/HalseySpicy/Geeker-Admin/tree/template

分步骤讲解前端框架中的每一个核心逻辑,讲一下顶部Header右侧的功能区域——用户个人中心模块,效果图:

fb9042150f5ca77708a5dd7852be688c.png

1、定义核心区域组件

还是老规矩,新建一个组件,

src\layouts\components\Header\ToolBarRight.vue,添加内容:

<template>
  <div class="tool-bar-ri">
    <div class="header-icon">
      <Message id="message" />
    </div>
    <span class="username">{{ username }}</span>
    <Avatar />
  </div>
</template>


<script setup lang="ts">
import { computed } from "vue";
import { useUserInfoStore } from "@/stores/userInfo";
import Message from "./components/Message.vue";
import Avatar from "./components/Avatar.vue";


const userStore = useUserInfoStore();
const username = computed(() => userStore.user?.uRealName ?? '管理员');
</script>

根据需要,今天只演示和保留了两个功能,分别是站内信Message和头像缩略图Avatar组件,基本骨架就这两个子组件,其他功能以后可以根据情况追加。

2、设计Avatar组件布局

主要包括头像、个人信息、修改密码和退出登录,前三个都是模拟的,还没有对接后端数据接口,以后再补充吧,重点说一下退出登录功能,稍微有一点逻辑在里边,

新建文件src\layouts\components\Header\components\Avatar.vue

<template>
  <el-dropdown trigger="click">
    <div class="avatar">
      <img src="@/assets/images/avatar.gif" alt="avatar" />
    </div>
    <template #dropdown>
      <el-dropdown-menu>
        <el-dropdown-item @click="openDialog('infoRef')">
          <el-icon>
            <User />
          </el-icon>个人信息
        </el-dropdown-item>
        <el-dropdown-item @click="openDialog('passwordRef')">
          <el-icon>
            <Edit />
          </el-icon>修改密码
        </el-dropdown-item>
        <el-dropdown-item divided @click="logout">
          <el-icon>
            <SwitchButton />
          </el-icon>退出登录
        </el-dropdown-item>
      </el-dropdown-menu>
    </template>
  </el-dropdown>
  <!-- 个人信息 -->
  <InfoDialog ref="infoRef"></InfoDialog>
  <!-- 修改密码 -->
  <PasswordDialog ref="passwordRef"></PasswordDialog>
</template>


<script setup lang="ts">
import { ref } from "vue";
import { useRouter } from "vue-router";
import { useAuthStore } from "@/stores/auth";
import { useTabsStore } from "@/stores/modules/tabs";
import { ElMessageBox, ElMessage } from "element-plus";
import InfoDialog from "./InfoDialog.vue";
import PasswordDialog from "./PasswordDialog.vue";


const router = useRouter();
const userStore = useAuthStore();
const tabStore = useTabsStore();


// 退出登录
const logout = () => {
  ElMessageBox.confirm("您是否确认退出登录?", "温馨提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning"
  }).then(async () => {
    // 1.执行退出登录接口,非必需
    // await logoutApi();


    // 2.清除 Token
    userStore.setToken("");
    tabStore.closeMultipleTab();


    // 3.重定向到登陆页
    router.replace('/login');
    ElMessage.success("退出登录成功!");
  });
};


// 打开修改密码和个人信息弹窗
const infoRef = ref<InstanceType<typeof InfoDialog> | null>(null);
const passwordRef = ref<InstanceType<typeof PasswordDialog> | null>(null);
const openDialog = (ref: string) => {
  if (ref == "infoRef") infoRef.value?.openDialog();
  if (ref == "passwordRef") passwordRef.value?.openDialog();
};
</script>

再补充下两个子组件——个人信息和修改密码,目前就是一个弹窗,以后再联调接口:

@ -0,0 +1,22 @@
<template>
  <el-dialog v-model="dialogVisible" title="修改密码" width="500px" draggable>
    <span>This is Password</span>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="dialogVisible = false">确认</el-button>
      </span>
    </template>
  </el-dialog>
</template>


<script setup lang="ts">
import { ref } from "vue";


const dialogVisible = ref(false);
const openDialog = () => {
  dialogVisible.value = true;
};


defineExpose({ openDialog });
</script>

这里需要理解一下VUE3的写法,比如:

defineExpose 是 <script setup> 特有的 API,用于公开组件的内部逻辑给父组件。通过这个指令,父组件可以调用子组件公开的方法。在这里,openDialog 方法被暴露出去,因此父组件可以通过引用来调用该方法,来改变 dialogVisible 的状态。

这段代码的主要作用是定义一个在内部管理对话框显示状态的逻辑,并将打开对话框的功能暴露出去,以便父组件可以控制子组件对话框的显示。

3、持久化用户信息到状态管理

在之前,写过一个用户信息到状态管理Pinia中的方法,地址是

src\stores\userInfo.ts。之前的逻辑是手动将数据放到localstorage中,手动来维护数据,但是这样会有一个问题,一刷新,当前账号的账号信息就会丢失,你可能会好奇,既然数据已经持久化到localstorage里了,为何刷新还会丢失,这是因为我们目前页面渲染的时候,用的是Pinia,不是像Vue2的时候,是手动从localstorage中取值的,如果要用Pinia来获取用户数据,而又要保证刷新页面不丢失,还是用上一节课我们说到的Pinia插件——pinia-plugin-persistedstate

修改的内容大概是这样的:

88d234ff2a44f5daaed36921f153bf64.png

import { defineStore } from 'pinia';
import piniaPersistConfig from "@/stores/config/piniaPersist";


export const useUserInfoStore = defineStore({
  id: 'userinfo',
  state: (): { user: User.UserResponse | null } => ({
    user: null
  }),
  actions: {
    setUser(user: User.UserResponse) {
      this.user = user;
    },
    clearUser() {
      this.user = null;
      localStorage.removeItem('userinfo');
    }
  },
  persist: piniaPersistConfig("userinfo")
});

所以,这个例子又一次证明,使用Pinia和localstorage可以完美的实现对所有的数据的操作和管理操作,还是建议多多使用。

4、模板文件引用,渲染效果

到这里就比较简单了,直接引用即可:

adb2a7bc53d9eccf557214ca7026b567.png

可以看到最终的渲染效果,没问题,试试路由跳转和页面刷新都没问题

6907ecf443fb93ff7c61ac337a8f692a.png

下篇文章我们继续对页面优化,实现第二种布局方式——横向布局,敬请期待。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值