vue3 ts setup 监听 pinia 数据的变化,更新页面数据

发布时间 2023-09-18 10:59:06作者: mcayear

简述

由于 pinia 导入到vue中的值没有响应性

import useUserStore from './stores/user';
const userStore = useUserStore();
userStore.isvaild;// 没有响应性

那么我们在vue中动态修改某值的想法则需要使用 vue 为我们提供的 watch 方法。Vue3文档

watch([userStore.isvaild, userStore.state.email], ([vaild, email], [prevIsvaild, prevEmail]) => {
  /* ... */
})

具体实现

创建和配置Pinia Store

// /stores/user.ts

import { defineStore } from 'pinia';
import { ref, type Ref } from 'vue';

interface UserState {
  username: string;
  email: string;
}

const useUserStore = defineStore('user', () => {
  const state: UserState = {
    username: '',
    email: ''
  };
  const isvaild: Ref<boolean> = ref(false);

  const setUser = (response: UserState) => {
    state.username = response.username;
    state.email = response.email;
    isvaild.value = true;
  };

  const getUsername = () => {
    return state.username;
  };

  const getEmail = () => {
    return state.email;
  };

  const logout = () => {
    isvaild.value = false;
    state.username = '';
    state.email = '';
  };

  return {
    isvaild,
    state,
    setUser,
    getUsername,
    getEmail,
    logout
  };
});

export default useUserStore;

在 Vue 组件中监听 Pinia 数据变化

  1. 这是模板内容,脚本内容在第2点
<!-- /App.vue -->
<template>
  <div id="app">
    <!-- 页眉导航栏 -->
    <header>
      <nav class="navbar navbar-expand-lg navbar-light bg-light">
            <!-- 用户登录状态 -->
            <div v-if="isLoggedIn">
              <HeaderIcon :email="userEmail" />
              <button @click="logout">Logout</button>
            </div>
            <!-- 未登录状态 -->
            <div v-else>
              <router-link to="/login">Login</router-link>
              <router-link to="/forgot-password">Forgot Password</router-link>
            </div>
      </nav>
    </header>

    <!-- 页面内容 -->
    <main>
      <!-- 使用 <router-view> 来呈现不同页面的内容 -->
      <router-view></router-view>
    </main>
  </div>
</template>

<script setup lang="ts">
// ...setup脚本内容
</script>
  1. setup脚本内容
// /App.vue
import { ref, onMounted, watch } from 'vue';
import axios from 'axios';
import { useRouter } from 'vue-router';
import useUserStore from './stores/user';
import HeaderIcon from '@/components/HeaderIcon.vue';

const userStore = useUserStore();
const router = useRouter();

const displayName = ref("");
const userEmail = ref("mcayear@163.com");
const isLoggedIn = ref(userStore.isvaild); // 是否已登录

onMounted(() => {
  axios.post(import.meta.env.VITE_SCISERVE + '/api/userinfo', {}, {
    headers: { 'Content-Type': 'application/json' },
  })
  .then((response) => {
    if (response.status >= 400 && response.status < 500) {
      throw new Error('Client error: ' + response.status);
    }

    if (response.data.success) {
      displayName.value = response.data.data.displayName;
      userEmail.value = response.data.data.email;
      userStore.setUser(response.data.data);
      isLoggedIn.value = true;
      router.push('/dashboard');
    } else {
      // showErrorPopup
      console.log(response.data.message);
    }
  })
  .catch((error) => {
    // showErrorPopup
    console.log(error.toString());
  });
});
watch(
    () => [userStore.isvaild, userStore.state.email],
    ([newVaild, newEmail], [oldVaild, oldEmail]) => {
      isLoggedIn.value = newVaild as boolean;
      userEmail.value = newEmail as string;
    }
  );
const logout = () => {
  isLoggedIn.value = false;
  userStore.logout();

  axios
  .post(import.meta.env.VITE_SCISERVE + '/api/logout', {}, {
    headers: { 'Content-Type': 'application/json' },
  })
  .then(() => {
    router.push('/login');
  })
  .catch((error) => {
    // showErrorPopup
    console.log(error.toString());
  });
};
  1. HeaderIcon.vue 内容
<!-- /components/HeaderIcon.vue -->
<template>
    <div>
        <img :src="gravatarUrl" alt="Gravatar" />
    </div>
</template>
  
<script setup lang="ts">
    import { computed } from 'vue';
    import { Md5 } from 'ts-md5'; // 详细教程: https://www.cnblogs.com/freejx/p/16934835.html

    const props = defineProps({
        email: String,
    });

    // 计算属性,根据邮箱生成Gravatar头像URL
    const gravatarUrl = computed(() => {
    const hash = Md5.hashStr((props.email|| "").trim().toLowerCase());
    return `https://www.gravatar.com/avatar/${hash}?s=100`;
    });
</script>