这周在做公司的后台管理项目,因为是突击项目做的比较简单。只需要做一个伪登录页面,和数据展示页面,考虑到后期需要,还是觉得用状态管理做一下登录逻辑。
最开始是准备使用Vue3新特性(?好像Vue2就存在,只是当时好像没有什么教程有讲这个API)
// 使用Vue3的setup语法糖(优点:减少代码量,组件引入自动注册,自动return setup 中定义的变量)
// App.vue
<script setup lang="ts">
import {provide,ref} from 'vue'
// 此处提供登录初始状态以及初始用户信息(以键值对的形式)
// 如 provide('isLogin',ref(false)) 表示登录状态为未登录
provide(key,value)
//...
</script>
// Login.vue 下级组件..
<script setup lang="ts">
import {inject} from 'vue'
// 使用inject获取上级组件中provide暴露出来的数据
// 如 inject('isLogin') 来获取登录状态 (inject获取出来的数据是响应式的)
const value = inject(key)
//...
</script>
然后想到后续会有登录相关的通用方法,重复的写显然不合适,于是准备在src目录下新建common目录,在里面编写通用方法并导出。
// src/common/index.ts
import {inject} from 'vue'
export function login(){
// ... 登录逻辑
// 修改登录状态
inject('isLogin').value = true;
// ... 登录后续处理(跳转/toast/message...)
}
export function loginout(){
// ... 登出逻辑
// 修改登录状态
inject('isLogin').value = false;
// ... 登出后续处理(跳转/toast/message...)
}
重新加载后发现控制台报了个 [vue warn]:inject() can only be used inside setup() or functional components.意思是inject方法只能使用在setup入口方法或者函数式组件内。不仅如此后续在组件外使用Vue-Router 的 useRouter/useRoute 、 Vuex 的useStore 、Vue3组件库Naive-UI Message组件的 useMessage 也会报同样的错。
后续通过查看Naive-UI message组件的useMessage部分ts源码,发现其类型是MessageApiInjection,推测其实现上应该是使用了Compostion provide和inject。
解决方案在naive-ui的文档中就有
将inject等注入组件挂载到window上使用,需要注意的是确保注入组件已经挂载成功(其实只需要使用ES6中的可选链操作符 `?.` 即可, window.injectFn?.fn);
不过最后我还是使用Vuex进行状态管理,总觉得provide和inject不是很适合当前场景...