如果你在项目中使用了 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'// 获取全局statelet data = getState('全局state对象中定义的对象key')
// 获取子模块中的 state// getState('子模块昵称') 获取到某个子模块中的state仓库对象let data = getState('signIn').SigninType

最后:

这样既扩展了功能 也不需要原本的vuex 先导入 在解构 在调用,并且对actions的控制和错误也做到了颗粒化捕获,与拦截反馈,在一定程度上提高了开发过程中的程序调试。

后来我又思考了一下感觉还能继续优化,比如像vue2中使用…mapActions 和…mapState 直接返回多个函数对象,感觉这样会比较优雅,但是在项目中我已经开发过半了 所以就没有对这个进行重新改造,有兴趣的可以试试。