element ui 原理简单分析

配置文件

这里大致说一下开发过程中经常用到的配置
config/dev.env.js
这里是开发过程中需要修改的一个地方

'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')

module.exports = merge(prodEnv, {
  NODE_ENV: '"development"',
  BASE_API: '"http://localhost:8443"', // 访问后端用到的基础地址,在src/utile/request中用到
})

config/index.js
这里大部分是webpack的基础配置一般不需要修改

 	host: 'localhost',
    port: 9527, // 前端服务器端口
    autoOpenBrowser: true, // 运行时自动打开浏览器
    errorOverlay: true,// 当编译器错误时在浏览器上显示全屏报错
    useEslint: true // 使用eslint

config/index.js 中 build 下有一个 assetsRoot 这里表示了打包时输出的位置

assetsRoot: path.resolve(__dirname, '../dist'),

在 build/webpack.base.conf.js 中 output 下的 path 中有引用 assetsRoot 设置输出路径

  entry: {
    app: './src/main.js' // 设置了webpack 入口文件为main.js
  },

以上的配置大部分在 build/webpack.base.conf.js 中使用,有兴趣深入了解的可以结合webpack官方文档了解。

首页和登陆

首先首页和登陆功能是如何实现的?
首先请看 src/views/login/index.vue 这个是框架的登录页面
注意一下 handleLogin 方法里面有这么一句

// 调用 store 中的 aciton 方法访问后端,成功则将路由跳转到 / 也就是主页
this.$store.dispatch('LoginByUsername', this.loginForm).then(() => {
     this.loading = false
     this.$router.push({ path: this.redirect || '/' })
   }).catch(() => {
     this.loading = false
   })

现在我们来看一下 store 中的 login 方法是怎么写的
src/store/modles/user.js
这里访问后端接口进行登录,成功返回 token 并保存到 store 和 cookie 中,然后执行上面的 this.$router.push({ path: this.redirect || ‘/’ }) 跳转路由到首页
失败则返回失败信息

// 用户名登录
    LoginByUsername({ commit }, userInfo) {
      const username = userInfo.username.trim()
      return new Promise((resolve, reject) => {
        loginByUsername(username, userInfo.password).then(response => {
          const data = response.data
           // 登陆成功后将后端返回的 token 保存到 store 和 cookie 中
          commit('SET_TOKEN', data.token)
          setToken(response.data.token)
          resolve()
        }).catch(error => {
          reject(error)
        })
      })
    },

登陆成功后,在跳转主页之前会执行 src/permission.js 里定义的路由的全局前置守卫 beforeEach

src/permission.js

router.beforeEach((to, from, next) => {
  NProgress.start() // NProgress 是一个进度条组件(在页面上方一个蓝色的进度条),这里表示启动进度条
  if (getToken()) { // 通过 getToken 方法从 cookie 中获取 token ,如果不存在则重定向到登录页
    /* 存在token */
    if (to.path === '/login') { //如果是登陆页,就重定向到主页
      next({ path: '/' })
      NProgress.done() // 进度条组件结束
    } else {
     // 当访问主页时,会执行下面这段逻辑获取用户权限信息
      if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
        store.dispatch('GetUserInfo').then(res => { // 访问后台拉取user_info
          const roles = res.data.roles // note: roles must be a array! such as: ['editor','develop']
          store.dispatch('GenerateRoutes', { roles }).then(() => { // 根据roles权限生成可访问的路由表
            router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
            next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
          })
        }).catch((err) => {
          store.dispatch('FedLogOut').then(() => {
            Message.error(err)
            next({ path: '/' })
          })
        })
      } else {
        // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
        if (hasPermission(store.getters.roles, to.meta.roles)) {
          next()
        } else {
          next({ path: '/401', replace: true, query: { noGoBack: true }})
        }
        // 可删 ↑
      }
    }
  } else {
    /* has no token*/
    if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
      next()
    } else {
      next(`/login?redirect=${to.path}`) // 否则全部重定向到登录页
      NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
    }
  }
})

请注意这里 store.dispatch(‘GenerateRoutes’, { roles }).then(()
这里调用了 src/store/modules/permission.js 中的 GenerateRoutes 来进行权限判断,大致逻辑是如果用户的角色包含 admin 就返回全部的动态路由。不包含 admin ,则调用 filterAsyncRouter 递归判断角色是否有路由的权限。具体判断代码在hasPermission中

/**
 * 通过meta.role判断是否与当前用户权限匹配
 * @param roles
 * @param route
 */
function  (roles, route) {
  if (route.meta && route.meta.roles) {
    return roles.some(role => route.meta.roles.includes(role)) // 这里判断了路由的.meta.roles 属性中是否包含 role 
  } else {
    return true
  }
}

到这里就可以看一下路由究竟是怎么写的了
element ui 原理简单分析_第1张图片
这里 asyncRouterMap 动态路由中都有一个 roles 属性,用于判断用户权限。
同时注意一下主页的路由,登陆成功后有这么一句重定向 this.$router.push({ path: this.redirect || ‘/’ }) 会触发下面的路由访问主页

{
    path: '',
    component: Layout,
    redirect: 'dashboard',
    children: [
      {
        path: 'dashboard',
        component: () => import('@/views/dashboard/index'),
        name: 'Dashboard',
        meta: { title: 'dashboard', icon: 'dashboard', noCache: true, affix: true }
      }
    ]
  },

你可能感兴趣的:(vue学习)