欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【微人事项目笔记】5、左边菜单栏前端页面开发,使用 vuex 存放数据

程序员文章站 2022-05-18 18:39:39
...


上一小节我们把查询menu的接口开发好了,那么这一小节就制作前端页面,把后台返回的数据展示出来。

后台返回的数据存放在vuex中,vuex中的数据是公共的,所有组件都可以访问到,另外vuex比sessionStorage相对安全。

1、安装vuex

npm install vuex

2、vuex的简单使用介绍

创建store.js,引入vuex,state中就是我们存放的数据,mutations中就是我们要改变数据的方法,改变 store 中的状态的唯一途径就是显式地提交 (commit) ,
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此我们可以调用 context.commit 提交一个 mutation。在这里本项目直接使用store.commit(‘initRouters’, 参数)来调用mutation。

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    // 数据
    state:{
        routes:[]
    },
    // 定义的回调函数,用来变更数据状态
    mutations:{
        initRouters(state, data) {
            state.routes = data
        }
    },
    // 提交mutation中的函数
    actions:{
    }
})

和前面的api.js同样需要在main.js中引入,

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from "./utils/store";
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import {postKeyValueRequest, postRequest,putRequest, getRequest, deleteRequest} from "./utils/api";
Vue.prototype.postKeyValueRequest = postKeyValueRequest;
Vue.prototype.postRequest = postRequest;
Vue.prototype.putRequest = putRequest;
Vue.prototype.getRequest = getRequest;
Vue.prototype.deleteRequest = deleteRequest;

Vue.config.productionTip = false

Vue.use(ElementUI);

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

后面就可以使用store了。

3、封装接收后台menu数据工具menus.js

【微人事项目笔记】5、左边菜单栏前端页面开发,使用 vuex 存放数据
menus.js,主要工作就是请求后端接口获取menus数据放在router.js和store中,把component字符串转成对应的组件,其他的依然是字符串格式。

import {getRequest} from "./api";

export const initMenu=(router, store) => {
    // 如果store中有数据 就直接返回
    if (store.state.routes.length > 0) {
        return;
    }
    getRequest("/system/config/menu").then(data=>{
        if (data && data.obj) {
            let fmtRouters = formatRouters(data.obj);
            router.addRoutes(fmtRouters);
            store.commit('initRouters', fmtRouters)
        }
    });
};

export const formatRouters = (routes) => {
    let fmRouters = [];

    routes.forEach(router=>{
        let{path, component, name, children} = router;
        if(children && children instanceof Array) {
            children = formatRouters(children)
        }
        let fmRouter = {path:path,name:name,children:children,
            // 把component字符串换成对应组件,动态导入
            component(resolve){
                require(['../views/'+component+'.vue'], resolve)
            }
        };
        fmRouters.push(fmRouter)
    });
    return fmRouters;
};

4、导航守卫,initMenu初始化菜单何时执行?

如果用户刷新页面就要执行一次初始化菜单的话,那么每个页面都要有执行initMenu的代码,其实我们可以使用导航守卫,判断一下用户在跳转的时候是不是去了登录页面,否则的话就执行initMenu。

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from "./utils/store";
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import {postKeyValueRequest, postRequest, putRequest, getRequest, deleteRequest} from "./utils/api";
import {initMenu} from "./utils/menus";

Vue.prototype.postKeyValueRequest = postKeyValueRequest;
Vue.prototype.postRequest = postRequest;
Vue.prototype.putRequest = putRequest;
Vue.prototype.getRequest = getRequest;
Vue.prototype.deleteRequest = deleteRequest;
Vue.prototype.initMenu = initMenu;
Vue.config.productionTip = false

Vue.use(ElementUI);
// 导航守卫
router.beforeEach((to, from, next) => {
    if (to.path == '/') {   // 回登录页
        next();
    } else {
        initMenu(router, store);
        next();
    }
});

new Vue({
    router,
    store,
    render: h => h(App)
}).$mount('#app')

Home.vue

<template>
    <div>
        <el-container class="homeContainer">
            <el-header class="homeHeader">
                <div class="title">微人事</div>
                <el-dropdown class="userInfo" @command="handleCommand">
                    <span class="el-dropdown-link">
                      {{user.name}}<i><img :src="user.userface" alt="用户头像"></i>
                    </span>
                    <el-dropdown-menu slot="dropdown">
                        <el-dropdown-item command="userinfo">个人中心</el-dropdown-item>
                        <el-dropdown-item command="setting">设置</el-dropdown-item>
                        <el-dropdown-item divided command="logout">注销登录</el-dropdown-item>
                    </el-dropdown-menu>
                </el-dropdown>
            </el-header>

            <el-container>
                <el-aside width="200px">
                    <el-menu @select="menuClick">
                        <!--                        循环加载router中的children-->
                        <!-- <el-submenu index="1" v-for="(item, index) in this.$router.options.routes" v-if="!item.hidden">-->
                        <el-submenu index="1" v-for="(item, index) in routes" v-if="!item.hidden">
                            <template slot="title">
                                <i class="el-icon-location"></i>
                                <span>{{item.name}}</span>
                            </template>
                            <el-menu-item :index="child.path" v-for="(child, indexj) in item.children">{{child.name}}
                            </el-menu-item>
                        </el-submenu>
                    </el-menu>
                </el-aside>

                <el-main>
                    <el-breadcrumb separator-class="el-icon-arrow-right" v-if="this.$router.currentRoute.path!='/home'">
                        <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
                        <el-breadcrumb-item>{{this.$router.currentRoute.name}}</el-breadcrumb-item>
                    </el-breadcrumb>
                    <div class="homeWelcome" v-if="this.$router.currentRoute.path=='/home'">
                        欢迎来到微人事!
                    </div>
                    <router-view></router-view>
                </el-main>
            </el-container>
        </el-container>
    </div>
</template>

<script>
    export default {
        name: 'Home',
        data() {
            return {
                user: JSON.parse(window.sessionStorage.getItem('user'))
            }
        },
        computed:{
            routes() {
                return this.$store.state.routes;
            }
        },
        methods: {
            menuClick(index, indexPath) {
                this.$router.push(index)
            },
            handleCommand(command) {
                if (command == 'logout') {
                    this.$confirm('此操作将注销登录, 是否继续?', '提示', {
                        confirmButtonText: '确定',
                        cancelButtonText: '取消',
                        type: 'warning'
                    }).then(() => {
                        this.getRequest('/logout')
                        window.sessionStorage.removeItem('user')
                        this.$router.replace('/')
                    }).catch(() => {
                        this.$message({
                            type: 'info',
                            message: '已取消操作'
                        });
                    });
                }
            }
        }
    }
</script>

<style>
    .homeHeader {
        background-color: #409eff;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0px 15px;
        box-sizing: border-box;
    }

    .homeHeader .title {
        font-size: 30px;
        font-family: 华光行楷_CNKI;
        color: #ffffff;
    }

    .homeHeader .userInfo {
        cursor: pointer;
    }

    .el-dropdown-link img {
        width: 48px;
        height: 48px;
        border-radius: 24px;
        margin-left: 8px;
    }

    .el-dropdown-link {
        display: flex;
        align-items: center;
    }
    .homeWelcome{
        text-align: center;
        font-size: 30px;
        color: #409eff;
    }
</style>

5、测试

【微人事项目笔记】5、左边菜单栏前端页面开发,使用 vuex 存放数据
使用songjiang,123登录之后,把查询到的menu展示出来了。
【微人事项目笔记】5、左边菜单栏前端页面开发,使用 vuex 存放数据

相关标签: 项目笔记