如果你在项目中使用了 vuex模块化,并且在项目中使用actions中函数调用频率高,推荐了解一下这种方式。
比如下面两种方式调用 ,
第一个是直接传参设置,
第二个是添加了异步ajax返回内容 在回调到等下我们要封装的js中的成功回调里,然后这个成功回调就会反馈给组件
1.创建文件utils/vueTool.js
import storage from '@/utils/storage.js'; import store from '@/store/index.js'; const { dispatch, state } = store; /** * @vuexFunc 调用vuex模块中的 Actions 并异步回调结果 * @param modules {string} 调用指定的子模块 如果是全局的可以不传 * @param funcName {string} 调用Actions 函数名称 * @param data {object} * @param followUp {string / object} * { data:{}, followUp:string / object function(res){} }, * data:当前调用接口需要的参数, * followUp 当前接口完成回调后 继续执行更新接口的 名称和参数 可以是请求地址字符串 可以是对象携带参数 * followUp:'URL' / followUp:{url:'请求接口地址',query:{参数}} * function回调函数 */ export function vuexFunc(modules = '', funcName = '', data = {}) { function send(followUp = '', query = null, lock = null) { // 消费凭证 if (typeof lock === 'number') { console.log('已消费:', lock) lock = true }; let url = ''; if (followUp) { url = followUp; } else { if (!modules && typeof modules !== 'boolean') { console.error('Actions函数名称是必填。'); return; }; url = `${modules?modules+'/':''}${funcName}`; }; // 开发中使用 校验当前调用的vuex模块是否存在 if (process.env.NODE_ENV === 'development') { let modulesName = followUp ? followUp.split('/')[0] : typeof modules === 'boolean' ? funcName :modules; if (storage.getItem('modulesKey').indexOf(modulesName) === -1) { console.error(`找不到 ${modulesName} 请检查!`); return; }; }; let queryData = {} if(typeof modules === 'boolean'){ queryData = data } else { queryData = followUp ? query ? query : {} :data.data && Object.keys(data.data).length?data.data:{} } dispatch(url, { // data: followUp ? query ? query : {} : data.data, data: queryData, callback(res) { // 成功 if (res !== 'failed') { if (lock) { console.log('停止了') return }; if (data.callback) { data.callback(res); }; if (data.followUp && typeof data.followUp === 'string') { console.log('开始后续回调') send(data.followUp, null, Date.now()); } else if (data.followUp && Object.keys(data.followUp).length) { if (!data.followUp.url) { console.error('缺少后续请求的url'); return; }; if (!data.followUp.hasOwnProperty('query')) { console.error('query字段 缺少后续请求的参数,没有参数直接传入 string Url 形参'); return; }; send(data.followUp.url, data.followUp.query, Date.now()) }; // 失败 -1 } else if (res === 'failed') { if (data.failed) { data.failed(res) } else { console.error('接口请求失败:'+url) } }; } }); }; send(); } /** * @getState 获取vuex中state仓库 * @param modules {string} 仓库名称 如果是子模块就传入子模块的名称 */ export function getState(modules = '') { if (!modules) { console.error('state仓库名称是必填。'); return; }; return state[modules] }
2.添加开发环境中的模块验证
注意:如果你的vue3项目是使用webpack5创建的 那么这里的自动化导入文件 就不能使用,可以去看看我上篇文章中有写webpack5如何自动化导入模块
import { createStore } from 'vuex' import actions from './actions' import mutations from './mutations' import storage from '@/utils/storage.js' const modulesFiles = import.meta.glob('./modules/*/index.js', { eager: true }); const modules = Object.keys(modulesFiles).reduce( (modules, path) => { const moduleName = path.replace(/^\.\/(.*)\.\w+$/, '$1') modules[moduleName.split('/')[1]] = modulesFiles[path]?.default return modules }, {} ); let modulesKey = ''; if(process.env.NODE_ENV === 'development'){ let obj = {...actions,...modules}; for(let key in obj){ modulesKey+=key+',' }; storage.setItem('modulesKey',modulesKey); }; const store = createStore({ modules, state: { name: 'allen', modulesKey:storage.getItem('modulesKey') || modulesKey, }, mutations, actions, getters: {} }) export default store
3.页面调用封装
actions函数的调用
import { vuexFunc, getState } from '@/utils/vueTool'; vuexFunc('子模块文件昵称','actions.js中定义的函数昵称',{ data:{接口需要的参数,或者你要设置到仓库的值}, callback(res){ // 请求回调 console.log(res) } }); //模式一(调用全局actions函数) vuexFunc(false,'setStageCourse',{ data:query, callback(res){ console.log(res) } }); //模式二(调用子模块函数中的actions函数) vuexFunc('index','setStageCourse',{ data:query, callback(res){ console.log(res) } }); // 模式三(调用完一个actions函数后立即执行另外一个actions函数) 这里调用完成signIn子模块中的loginByCode函数完成回调后,会立即去读取followUp的配置
也是对应了 子模块/signIn函数昵称去执行,followUp允许一个具体的函数路径或者一个对象可以配置函数要设置的值
vuexFunc('signIn','loginByCode',{ data:{code:wxcode.value}, followUp:'index/getConfig', callback(res){ SignType.value = false storage.setItem('authorization',res.data.token); } });
state仓库的使用
import {vuexFunc,getState} from '@/utils/vueTool' // 获取全局state let data = getState('全局state对象中定义的对象key')
// 获取子模块中的 state // getState('子模块昵称') 获取到某个子模块中的state仓库对象 let data = getState('signIn').SigninType
最后:
这样既扩展了功能 也不需要原本的vuex 先导入 在解构 在调用,并且对actions的控制和错误也做到了颗粒化捕获,与拦截反馈,在一定程度上提高了开发过程中的程序调试。
后来我又思考了一下感觉还能继续优化,比如像vue2中使用 ...mapActions 和 ...mapState 直接返回多个函数对象,感觉这样会比较优雅,但是在项目中我已经开发过半了 所以就没有对这个进行重新改造,有兴趣的可以试试。