Vue3全局共享数据

1,Vuex

vue2 的官方状态管理器,vue3 也是可以用的,需要使用 4.x 版本

相对于 vuex3.x,有两个重要变动:

  • 去掉构造函数 Vuex,而使用 createStore() 创建仓库
  • 为了配合 compositionAPI,新增 useStore() 获取仓库对象

先看一个使用 vuex 的例子:实现登录、刷新页面恢复登录、退出登录的状态管理。

// store/index.js
import loginUser from "./loginUser";
import { createStore, createLogger } from "vuex";
export default createStore({
  modules: {
    loginUser,
  },
  plugins: [createLogger()], // 用于调试,会在控制台打印日志。
});

createLogger 官网参考

// store/loginUser.js
export default {
  namespaced: true,
  state: {
    user: null,
    loading: false,
  },
  mutations: {
    setUser(state, payload) {
      state.user = payload;
    },
    setLoading(state, payload) {
      state.loading = payload;
    },
  },
  actions: {
    async login({ commit }, { loginId, loginPwd }) {
      commit("setLoading", true);
      // 登录接口
      const user = await _faker.login(loginId, loginPwd);
      commit("setUser", user);
      commit("setLoading", false);
      return user;
    },
    async loginOut({ commit }) {
      commit("setLoading", true);
      // 退出登录接口
      await _faker.loginOut();
      commit("setUser", null);
      commit("setLoading", false);
    },
    async whoAmI({ commit }) {
      commit("setLoading", true);
      // 恢复登录接口
      const user = await _faker.whoAmI();
      commit("setUser", user);
      commit("setLoading", false);
    },
  },
};

组件中使用 store

<script setup>
import { computed, ref } from "vue";
import { useStore } from "vuex";

const store = useStore();

const loginId = ref("");
const loginPwd = ref("");
const loading = computed(() => store.state.loginUser.loading),

const handleSubmit = async () => {
  const user = await store.dispatch("loginUser/login", {
    loginId: loginId.value,
    loginPwd: loginPwd.value,
  });
  if (user) {
     // 登录成功,跳转首页。
  } else {
    alert("账号/密码错误");
  }
};
</script>

注册

// main.js
import { createApp } from "vue";
import App from "./App.vue";
import store from "./store";
createApp(App).use(store).mount("#app");

// 恢复登录,其实就是把存在本地的用户信息,再次放到 store 中。
store.dispatch("loginUser/whoAmI");

2,provide & inject

vue2 中就有这2个配置,可以在祖先组件中注入数据,然后在后代组件中使用。

vue3 的 optionAPI 做了兼容的同时,compositionAPI 也提供了 provide()inject()-官网-依赖注入

另外,考虑到部分数据会在整个 vue 应用中使用,所以 vue3 在应用实例中也添加了 provide(), 用于提供整个应用的共享数据

import { createApp } from "vue";
import App from "./App.vue";
creaetApp(App)
  .provide("foo", ref(1))
  .provide("bar", ref(2))
  .mount("#app");

来模仿 vuex 的使用方式来实现上面的例子。

// store/index.js
import { provideStore as provideLoginUserStore } from "./useLoginUser";
// 继续导入其他共享数据模块...
// import { provideStore as provideNewsStore } from "./useNews"

// 提供统一的数据注入接口
export default function provideStore(app) {
  provideLoginUserStore(app);
  // 继续注入其他共享数据
  // provideNewsStore(app);
}
// store/userLoginUser.js
import { readonly, reactive, inject } from "vue";
const key = Symbol(); // Provide的key

// 在传入的vue应用实例中提供数据
export function provideStore(app) {
  // 创建默认的响应式数据
  const state = reactive({ user: null, loading: false });
  // 登录
  async function login(loginId, loginPwd) {
    state.loading = true;
    const user = await _faker.login(loginId, loginPwd);
    state.user = user;
    state.loading = false;
  }
  // 退出
  async function loginOut() {
    state.loading = true;
    await _faker.loginOut();
    state.loading = false;
    state.user = null;
  }
  // 恢复登录状态
  async function whoAmI() {
    state.loading = true;
    const user = await _faker.whoAmI();
    state.loading = false;
    state.user = user;
  }
  // 提供全局数据
  app.provide(key, {
    state: readonly(state), // 对外只读
    login,
    loginOut,
    whoAmI,
  });
}

export function useStore(defaultValue = null) {
  return inject(key, defaultValue);
}

组件中使用 store

<script setup>
import { computed, ref } from "vue";
import { useStore } from "../store/useLoginUser";

const store = useStore();

const loginId = ref("");
const loginPwd = ref("");
const loading = computed(() => store.state.loading),

const handleSubmit = async () => {
  const user = await store.login(loginId.value, loginPwd.value);
  if (store.state.user) {
     // 登录成功,跳转首页。
  } else {
    alert("账号/密码错误");
  }
};
</script>

全局注册

// main.js
import { createApp } from "vue";
import App from "./App.vue";
import provideStore from "./store";
const app = createApp(App);
provideStore(app); // 上面的封装形式,即便项目中存在多个应用实例,也可以应对。
app.mount("#app");

// 恢复登录,要放到 App.vue 中执行了。
// whoAmI();

2,global state

得益于 vue3 的响应式系统是可以脱离组件而存在,所以可轻松创建多个全局响应式数据。

// store/useLoginUser.js
import { reactive, readonly } from "vue";

// 创建默认的全局单例响应式数据,仅供该模块内部使用
const state = reactive({ user: null, loading: false });

// 对外暴露的数据是只读的,不能直接修改
export const loginUserStore = readonly(state);

// 登录
export async function login(loginId, loginPwd) {
  state.loading = true;
  const user = await _faker.login(loginId, loginPwd);
  state.user = user;
  state.loading = false;
}
// 退出
export async function loginOut() {
  state.loading = true;
  await _faker.loginOut();
  state.loading = false;
  state.user = null;
}
// 恢复登录状态
export async function whoAmI() {
  state.loading = true;
  const user = await _faker.whoAmI();
  state.loading = false;
  state.user = user;
}

组件中使用 store

<script setup>
import { computed, ref } from "vue";
import { loginUserStore, login } from "../store/useLoginUser";

const loginId = ref("");
const loginPwd = ref("");
// 模版也可以直接使用 loginUserStore.loading
const loading = computed(() => loginUserStore.loading),

const handleSubmit = async () => {
  const user = await login(loginId.value, loginPwd.value);
  if (user) {
     // 登录成功,跳转首页。
  } else {
    alert("账号/密码错误");
  }
};
</script>

全局注册

// main.js
import { createApp } from "vue";
import App from "./App.vue";
import { whoAmI } from "./store/useLoginUser";
createApp(App).mount("#app");

// 恢复登录
whoAmI();

4,Pinia

官网参考

5,对比

vuexglobal stateProvide&Inject
组件数据共享
可否脱离组件
量级

以上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

下雪天的夏风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值