0.0.1 • Published 3 years ago
@loushangvue/layout v0.0.1
插件基于vue-element-admin
项目封装,推荐基于vue-element-admin
开发的项目使用本插件,项目目录
├── build # 构建相关
├── mock # 项目mock 模拟数据
├── plop-templates # 基本模板
├── public # 静态资源
│ │── favicon.ico # favicon图标
│ └── index.html # html模板
├── src # 源代码
│ ├── api # 所有请求
│ ├── assets # 主题 字体等静态资源
│ ├── components # 全局公用组件
│ ├── directive # 全局指令
│ ├── filters # 全局 filter
│ ├── icons # 项目所有 svg icons
│ ├── lang # 国际化 language
│ ├── layout # ********************插件基于layout封装**************************#
│ ├── router # 路由
│ ├── store # 全局 store管理
│ ├── styles # 全局样式
│ ├── utils # 全局公用方法
│ ├── views # views 所有页面
│ ├── App.vue # 入口页面
│ ├── main.js # 入口文件 加载组件 初始化等
│ └── permission.js # 权限管理
├── tests # 测试
├── .env.xxx # 环境变量配置
├── .eslintrc.js # eslint 配置项
├── .babelrc # babel-loader 配置
├── .travis.yml # 自动化CI配置
├── vue.config.js # vue-cli 配置
├── postcss.config.js # postcss 配置
└── package.json # package.json
注意:删除项目中的layout文件夹,取消styles/sidebar.scss
样式文件引入,防止样式冲突,其他如提示信息根据具体样式,自行更改
快速开始
npm install @vuelement/layout --save
项目配置
main
// main.js文件
// 引入插件样式
import '@vuelement/layout/src/styles/index.scss'
// 可以通过init来初始化项目,init封装了keycloak
import { init } from '@vuelement/layout'
init(Vue, {
el: '#app',
router,
store,
i18n,
render: h => h(App)
}).catch(err => console.error(err))
// 如果要引入项目中的面包屑Breadcrumb组件,可以通过bindComponent方法来使用
import { bindComponent } from '@vuelement/layout'
import Breadcrumb from '@/components/Breadcrumb'
// 1.通过init方法来使用
init(Vue, {
el: '#app',
router,
store,
i18n,
render: h => h(App)
}).then(ret => bindComponent(Vue, Breadcrumb))
.catch(err => console.error(err))
// 2.在vue初始化后,调用 bindComponent(Vue, Breadcrumb)
router
// router/index.js
import Layout from '@vuelement/layout/src/layout/Layout.vue'
[{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [{
path: 'dashboard',
name: 'Dashboard',
component: () => import('@/views/dashboard/index'),
meta: { title: 'Dashboard', icon: 'dashboard' }
}]
},
{
path: '/example',
component: Layout,
redirect: '/example/table',
name: 'Example',
meta: { title: 'Example', icon: 'dashboard' },
children: [
{
path: 'table',
name: 'Table',
component: () => import('@/views/table/index'),
meta: { title: 'Table' }
},
{
path: 'tree',
name: 'Tree',
component: () => import('@/views/tree/index'),
meta: { title: 'Tree' }
}
]
}]
注意:1. 图标icon仅支持svg
格式,并且要在icons/icon文件夹中一一对应;
store
// store/index.js
import getters from './getters'
import layoutStore from '@vuelement/layout/src/store' // 引入插件的store模块
import { bindRoutes } from '@vuelement/layout'
Vue.use(Vuex)
const { headerApp, headerUser, headerGetters } = { ...layoutStore } // 引入插件的store模块
bindRoutes("authRoutes") // 引入权限过滤之后的路由数组,authRoutes为getters中对应的名称,用户自行更改
// 1.第一种写法
const store = new Vuex.Store({
modules: {
headerApp,
headerUser,
... // 添加合并模块
},
getters: Object.assign(getters, headerGetters) // 添加合并模块
})
// 第二种写法
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
// set './app.js' => 'app'
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath)
modules[moduleName] = value.default
return modules
}, {})
// 添加合并模块
Object.assign(modules, { headerApp, headerUser})
const store = new Vuex.Store({
modules,
getters: Object.assign(getters, headerGetters) // 添加合并模块
})
// getters.js
const getters = {
...,
authRoutes: state => state.xxxx.authRoutes, // 用户自行更改
...
}
export default getters
配置文件
// public/config/config.json
{
// sidebar所显示的系统名称
"systemName": "事件总线",
"baseUrl": "http://yzh.inspur.com/",
// 当前环境
"environment": "prod",
// 测试开发环境
"dev": {
"clientId": "yunzhou", // keycloak clientId
"realm": "picp", // keycloak realm
"consoleUrl": "http://service-test.yzh.inspur.com/apistore/apis", // 获取链接列表的地址
},
// 生产环境
"prod": {
"clientId": "yunzhou",
"realm": "picp",
"consoleUrl": "http://service.yzh.inspur.com/apistore/apis", // 获取链接列表的地址
},
// xxx环境
"xxx": {
...: ...
}
// 其他配置
...,
"layout": {
"sidebar": false,
"route": ""
}
}
加载配置文件
// main.js
import {init, loadConfig } from '@vuelement/layout'
// 1.可以通过init方法来加载配置,默认配置文件放在public/config/config.json,也可以指定路径path
init(Vue, options, path) // Vue, options用来初始化Vue
页面缓存问题
<!-- layout/components/AppMain.vue 文件-->
<section class="app-main" :style="{'top': hasNavbar ? '56px' : '0'}">
<transition name="fade-transform" mode="out-in">
<keep-alive>
<!-- 需要缓存的视图组件 -->
<router-view v-if="$route.meta.noCache === false"></router-view>
</keep-alive>
</transition>
<transition name="fade-transform" mode="out-in">
<!-- 不需要缓存的视图组件 -->
<router-view v-if="$route.meta.noCache === true || $route.meta.noCache === undefined"></router-view>
</transition>
</section>
子路由的侧边栏渲染问题
通过在子路由元数据中添加activeMenu
字段来控制当前路由未在侧边栏显示时,侧边栏选中的路由地址,'activepath'
代表侧边栏选中的路由地址
meta: {
activeMenu: 'activepath'
}
token
token存放由Session Storage转为cookie, key值改为前缀+inspur_token
,操作token的方法可以通过插件引入
import { CookieService } from '@vuelement/layout'
token相关更新
token的相关操作不在通过引入单个函数来进行,改为提供一个CookieService
的实例对象CookieService
来保存和操作token的相关信息(当前token仍然存在cookie中)
export class CookieService {
static TokenKey = 'inspur_token'
static RefreshToken = 'refresh_token'
static AuthKey = 'auth'
static IsLoginValid = 'isLoginValid'
static OldTokenKey = 'token'
prefix = ''
domain = ''
auth = null
constructor() {
this.domain = CookieService.getDomain()
}
static getDomain () {
const hostname = window.location.hostname
if (validDomainName(hostname)) {
return '.' + hostname.split('.').slice(-2).join('.')
} else {
return hostname
}
}
// 设置前缀
setPrefix (prefix) {
this.prefix = !!prefix ? prefix + '_' : ''
}
// 获取前缀
getPrefix () {
return this.prefix
}
// 获取token
getToken () {
return Cookies.get(this.prefix + CookieService.TokenKey)
}
// 设置token
setToken (token) {
sessionStorage.setItem(CookieService.OldTokenKey, token)
Cookies.set(this.prefix + CookieService.TokenKey, token, { domain: this.domain })
}
// 移除token
removeToken () {
sessionStorage.removeItem(CookieService.OldTokenKey)
Cookies.remove(this.prefix + CookieService.TokenKey, { domain: this.domain })
}
// 设置refresh_token
setRefreshToken (refreshToken) {
Cookies.set(this.prefix + CookieService.RefreshToken, refreshToken, { domain: this.domain })
}
// 获取refresh_token
getRefreshToken () {
return Cookies.get(this.prefix + CookieService.RefreshToken)
}
// 移除refresh_token
removeRefreshToken () {
Cookies.remove(this.prefix + CookieService.RefreshToken, { domain: this.domain })
}
// 设置IsLoginValid
setIsLoginValid (isLoginValid) {
Cookies.set(this.prefix + CookieService.IsLoginValid, isLoginValid, { domain: this.domain })
}
// 获取IsLoginValid
getIsLoginValid () {
return Cookies.get(this.prefix + CookieService.IsLoginValid)
}
// 移除IsLoginValid
removeIsLoginValid () {
Cookies.remove(this.prefix + CookieService.IsLoginValid, { domain: this.domain })
}
// 设置auth
setAuth(tokenInfo) {
this.auth = {
inspur_token: tokenInfo.token,
idToken: tokenInfo.idToken,
refreshToken: tokenInfo.refreshToken
}
}
// 获取auth
getAuth() {
return this.auth
}
// 清除cookie中的信息
clear () {
this.removeToken()
this.removeRefreshToken()
this.removeIsLoginValid()
}
}
CookieService使用
ConfigService、CookieService
均可通过import { ConfigService, CookieService } from '@vuelement/layout'
引入
import { ConfigService, CookieService } from '@vuelement/layout'
const name = ConfigService.getSystemName()
console.log(name)
const token = cookieService.getToken()
config.headers['Authorization'] = 'Bearer ' + token
也可以通过import { ServiceFactory } from '@vuelement/layout'
引入工厂类来创建服务
import { ServiceFactory } from '@vuelement/layout'
// 服务创建使用单例模式,在各处创建的服务实例为同一个
const CookieService = ServiceFactory.getConfigService()
const cookieService = ServiceFactory.getCookieService()
解决在其他应用退出后,vue项目没跳转到登陆页面的问题
在request.js中,引入CookieService,在请求配置时调用CookieService中的checkToken方法,并将原有设置header的代码注释掉。
例:
import { CookieService } from '@vuelement/layout'
service.interceptors.request.use(
config => {
// 1、检查token是否存在,如果存在,方法内部会添加header;如果不存在,方法内部的处理是跳转到登录页
CookieService.checkToken(config)
// 2、原有设置token的方法可注释掉
//if (store.getters.layoutToken) {
//config.headers['Authorization'] = 'Bearer ' + store.getters.layoutToken
//}
return config
}
)
不需要登录或者登录失效仍然能访问的接口需要在request中添加"auth: false"属性
0.0.1
3 years ago