在vue2中,提供了provide和inject配置,可以让开发者在高层组件中注入数据,然后在后代组件中使用
除了兼容vue2的配置式注入,vue3在composition api 中添加了provide和inject方法,可以在setup函数中注入
和使用数据
基本使用
provide('key',value)
// app.vue 定义数据 <script setup> import { provide,ref } from 'vue' const sum = ref(1) provide('foo',sum) </script>
// 其他页面调用 <script setup> import { inject } from 'vue' let foo = inject('foo')//传入key 在其他任意页面都能获取到 console.log(foo.value)// 1 </script>
考虑到有些数据需要在整个vue应用中使用,vue还在应用实列中加入了provide方法,用于提供整个应用的共享数据
creaetApp(App).provide('fpp',ref(1)).provide('foo',ref(2)).mount('#app')
因此,我们可以利用这一点,在整个vue应用中提供共享数据
目录结构:
模块封装
userSever.js
// 模拟ajax api接口使用 const userSery = { // 登录接口 login: (name,age) =>{ // 接口返回用户数据 储存在本地 return new Promise((resolve,reject)=>{ setTimeout(()=>{ let user = { name :name, age:age } window.sessionStorage.setItem('user',JSON.stringify(user)) console.log('登录成功') resolve(user) },1000) }) }, // 退出登录 loginOut:()=>{ return new Promise((resolve,reject)=>{ setTimeout(()=>{ window.sessionStorage.removeItem('user') resolve('退出成功') },1000) }) }, // 恢复登录 whoAmI:()=>{ // 读取本地储存的用户数据 return new Promise((resolve,reject)=>{ setTimeout(()=>{ let user = window.sessionStorage.getItem('user'); if(user){ user = JSON.parse(user); console.log('恢复成功',user) resolve(user); } else { reject('恢复失败'); }; },1000) }) } } // store 提供当前登录用户的共享数据 import { readonly,reactive,inject } from 'vue'; const key = Symbol(); // 在传入的vue应用实列中提供数据 export function provideStore(app){ // 创建默认的响应式数据 const state = reactive({user:null,loading:false}); // 登录 async function login (loginId,loginPwd){ state.loading = true const user = await userSery.login(loginId,loginPwd); state.user = user; state.loading = false } // 退出 async function loginOut (){ state.loading = true await userSery.loginOut(); state.user = null; state.loading = false } // 恢复登录状态 async function whoAmI (){ state.loading = true try { const user = await userSery.whoAmI(); state.user = user; state.loading = false } catch (e) { state.user = null; } state.loading = false } app.provide(key,{ state:readonly(state), // 对外只读 login, loginOut, whoAmI }) } export function useStore(defaultValue = null){ return inject(key,defaultValue) }
封装注入模块给app
src/store/index.js
import { provideStore as provideLoginUserStore } from "./userSever.js" // 继续导入其他共享数据模块... // import {provideStore as provideNewsStore } from './sueNew.js' // 提供统一的数据注入接口 export default function provideStore (app){ provideLoginUserStore(app); // 继续注入其他共享数据 // provideNewsStore }
main.js导入并且注入app
import { createApp } from 'vue' import App from './App.vue' import router from './router' import provideStore from './store' const app = createApp(App).use(router); provideStore(app) // 提供所有共享数据 app.mount('#app') // createApp(App).use(store).use(router).mount('#app')
到这里就已经完成了 全部准备工作
在你想调用的地方和页面进行下面引入和使用
import { useStore} from '../store/userSever.js' const Store = useStore() console.log(Store.state); //定义的state响应式数据 // 下面调用 导入模块的指定的函数方法去修改 state共享的响应式数据内容 // 点击 登录 const loginEvent = ()=>{ Store.login('allen',18) }; // 退出登录 const loginOutEvent = ()=>{ Store.loginOut() }; // 恢复登录 Store.whoAmI()
共享响应式数据,在A页面使用到了state,在B页面去调用函数改变 state 那么A页面的state数据也会发送改变,只要使用到的
state的地方都会响应式改变数据,相比vuex 更加轻量级 更加具有自定义扩展的能力,因为他本身不依赖任何第三方插件,完全是靠
vue本身提供的独立响应式系统来实现的。