vue2.x项目学习-首页(二)

登录成功后,通过修改pageType的值 -> 跳转到首页

this.$store.commit('setPage', this.$variable.pageType.NORMAL)
<template>
    <div id="app">
        <skin></skin>
        <!--<el-button type="primary" @click="$store.commit('skinToggle', true)">切换皮肤</el-button>-->
        <login v-if="$store.state.pageType === pageType.LOGIN"></login>
        <master v-else></master>
    </div>
</template>

简单了解一下src/config/store.js文件:

export default {
    state: {},
    mutations: {},
    actions: {}
}

state:Vuex 中用于存储应用的状态数据(类似于java项目里设置的全局变量,也是基于内存存储的)。

mutations:用于<font color="red">同步</font>修改 state 中的数据(类似于java项目里的set方法),第一个参数总是 state,第二个参数是 payload,表示传递给 mutation 的数据。

actions:用于<font color="red">异步</font>修改 state 中的数据,也可以提交 mutations 来修改状态(执行网络请求、定时器相关操作时,使用async……await……拿到结果,并能返回一个Promise),第一个参数是 context 对象,包含 state、commit、dispatch 等,可以通过<font color="red">解构赋值</font>的方式获取context对象里面的属性,比如:{ state, commit }。

一般情况下,只有一个store.js文件,store里面可以细分modules

const store = new Vuex.Store({
  modules,
  getters
})

getters:可以将其理解为store的计算属性,接收state 作为参数。

// 通过 Webpack 的 require.context 方法创建的对象,允许批量导入符合特定模式的模块
const modulesFiles = require.context('./modules', true, /\.js$/)

// keys():返回一个包含所有匹配文件路径的数组,reduce() 遍历所有模块文件路径,并将每个模块注册到 Vuex store
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
  const value = modulesFiles(modulePath)
  modules[moduleName] = value.default
  return modules
}, {})

关于Master.vue文件-首页文件:

在 created 钩子中进行数据获取是一个常见的做法,因为此时实例已经准备好,可以立即开始数据请求

created() {
    const query = this.$route.query
    if (query.token) {
        if(!query.isAllPage){
            this.fromOut = true
        }
        this.$help.token.set(query.token)
    }

    if (this.$help.token.get()) {
        this.$help.goPage = this.goPage
        this.$help.getPageAndSetAttr=this.getPageAndSetAttr
        this.$help.getAttr=this.getAttr
        this.$store.dispatch('getUser')
            .then(res => {
                if(res.sysFirst) {
                    this.pwdUpdate()
                    this.pwd.isForce = true
                }
            })
            .catch(this.$help.loaded)
            .finally(() => {
                const self = this
                const el = document.querySelector('.el-tabs__nav')
                if (el) {
                    el.oncontextmenu = e => {
                        self.deleteKey = e.target.id.split('-')[1]
                        let x = e.clientX
                        let y = e.clientY
                        self.$refs.closeTab.style.left = x + 'px'
                        self.$refs.closeTab.style.top = y + 'px'
                        self.isRight = true
                        e.preventDefault()
                    }
                    document.body.addEventListener('click', () => self.isRight = false)
                }
                this.loadMenu()

                // 关闭tab
                this.$help.closeCurrent = this.removeTab
            })
    } else {
        this.$store.commit('setPage', this.$variable.pageType.LOGIN)
    }
}

使用this.$route.query,this.route是 Vue Router 提供的一个对象,用于访问当前路由的查询参数,返回的是一个key: value对的json对象,另外还有一个全局属性`this.router`.push,可以导航到不同的URL。

完成的操作是:loginUserInfo(获取用户信息)-> menuNave(加载菜单项)


watch: {
    '$store.state.inputInfo.show'(val) {
        if (val) {
            this.form = this.$store.state.inputInfo.form
        }
    }
}

watch是vue的侦听器,一般形式都是属性名(newVal, oldVal)的方式,也可以通过:$store.state.inputInfo.show'(val)这种方式用来监听Vuex状态的变化。

另外还有计算属性:计算属性用于基于其他数据属性派生出新的值,并且<font color="red">会自动缓存结果</font>。侦听器用于监听某个数据的变化,并在变化时执行特定的操作。与计算属性不同,<font color="red">侦听器不会缓存结果</font>。

关于this.loadMenu()方法(加载菜单项):

methods: {
    loadMenu() {
        const query = this.$route.query
        let pathConfig = {
            // 主页
            index: {
                key: 'index',
                value: '主页',
                component: loadComponent('index/Index'),
            },
        }
        this.$help.loading(this.fromOut ? '' : '菜单加载中...')
        this.$api.post('sys/menu/menuNave')
            .then(res => {
                this.menu = res.data.map(item => {
                    item.target = item.menuCode
                    item.children.map(child => {
                        child.target = child.menuCode
                        return child
                    })
                    return item
                })

                const authObj = {}
                this.menu.forEach(parent => {
                    parent.children.forEach(child => {
                        if (child.target === 'empty') {
                            pathConfig[`${parent.target}_${child.target}`] = {
                                auth: child.id,
                                key: `${parent.target}_${child.target}`,
                                menu: child,
                                value: child.menuName,
                                component: loadComponent('error/Empty')
                            }
                        } else {
                            // 列表页面
                            pathConfig[`${parent.target}_${child.target}`] = {
                                auth: child.id,
                                key: `${parent.target}_${child.target}`,
                                base:`${parent.target}_${child.target}`,
                                menu: child,
                                value: child.menuName,
                                component: loadComponent(`${parent.target}/${child.target}/Main`)
                            }
                            // 新增页面
                            pathConfig[`${parent.target}_${child.target}Add`] = {
                                key: `${parent.target}_${child.target}Add`,
                                base:`${parent.target}_${child.target}`,
                                auth: child.id,
                                value: child.menuName + '新增',
                                menu: child,
                                component: loadComponent(`${parent.target}/${child.target}/Add`)
                            }
                            // 修改和详情页面
                            pathConfig[`${parent.target}_${child.target}DetailModify`] = {
                                auth: child.id,
                                key: `${parent.target}_${child.target}DetailModify`,
                                base:`${parent.target}_${child.target}`,
                                value: child.menuName ,
                                menu: child,
                                component: loadComponent(`${parent.target}/${child.target}/DetailModify`)
                            }
                        }
                        // 保存菜单
                        const auth = {}
                        child.children.forEach(menu => {
                            auth[menu.menuCode] = true
                        })
                        authObj[child.id] = auth
                    })
                })
    }
}

主要做的操作是:加载菜单 -> 根据菜单项的层级塞到pathConfig这个对象里面。

使用pathConfig[${parent.target}_${child.target}]:

pathConfig[{parent.target}_{child.target}] 是一种动态键名的对象属性访问方式。pathConfig 是一个对象,存储了页面路径配置。{parent.target}_{child.target} 是一个模板字符串,用于生成对象的键名。通过这种方式可以动态地为每个菜单项组合生成唯一的键名,并在 pathConfig 对象中存储对应的页面配置信息。

这里探讨一下为啥点击主菜单的子菜单页面内容能发生变化:

<el-main class="my-main">
    <template v-for="item in pathConfig">
        <component :key="item.key" :is="item.component" :ref="item.key" :page-param="item"
                   v-if="isShowTab(item.key)" :class="{ active:isMe(item.key) }"></component>
    </template>
</el-main>

上面pathConfig 中的配置信息已经装载成功。<component> 元素结合 :is 属性可以动态地渲染不同的组件的标签页的信息。每次点击菜单项后,menuTab 会被更新为新选择的标签页的标识符,这将触发 v-if="isShowTab(item.key)" 的重新计算,从而显示或隐藏相应的组件。

通过loadComponent加载组件

function loadComponent(url) {
    return () => import(`@/pages/${url}`)
}

另外一种方式:

export const loadMenus = (next, to) => {
  buildMenus().then(res => {
    const sdata = JSON.parse(JSON.stringify(res))
    const rdata = JSON.parse(JSON.stringify(res))
    const sidebarRoutes = filterAsyncRouter(sdata)
    const rewriteRoutes = filterAsyncRouter(rdata, false, true)
    rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })

    store.dispatch('GenerateRoutes', rewriteRoutes).then(() => { // 存储路由
      router.addRoutes(rewriteRoutes) // 动态添加可访问路由表
      next({ ...to, replace: true })
    })
    store.dispatch('SetSidebarRouters', sidebarRoutes)
  })
}

通过 router.addRoutes动态添加访问路由表

<el-scrollbar wrap-class="scrollbar-wrapper">
  <el-menu
    :default-active="activeMenu"
    :collapse="isCollapse"
    :background-color="variables.menuBg"
    :text-color="variables.menuText"
    :active-text-color="variables.menuActiveText"
    :collapse-transition="false"
    unique-opened
    mode="vertical"
  >
    <sidebar-item v-for="route in sidebarRouters" :key="route.path" :item="route" :base-path="route.path" />
  </el-menu>
</el-scrollbar>

点击子菜单时,页面切换是通过 el-menu 组件的 default-active 属性和 SidebarItem 组件实现的。default-active 绑定到 activeMenu 计算属性,该属性根据当前路由的 meta.activeMenu 或 path 来确定激活的菜单项。SidebarItem 组件会根据路由信息生成菜单项,并在点击时导航到相应的页面

<template>
  <!-- eslint-disable vue/require-component-is -->
  <component v-bind="linkProps(to)">
    <slot />
  </component>
</template>

当菜单项只有一个子菜单且不隐藏时,使用 app-link 组件进行导航。

结尾

giao!!!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容