{"id":14976427,"url":"https://github.com/dave-wind/vpc","last_synced_at":"2026-03-07T04:31:01.035Z","repository":{"id":174889517,"uuid":"132444540","full_name":"dave-wind/VPC","owner":"dave-wind","description":"Vue Permission Control","archived":false,"fork":false,"pushed_at":"2018-07-19T10:26:01.000Z","size":393,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-02-01T08:03:34.919Z","etag":null,"topics":["easymock","element-ui","flyio","vue-router","vuejs2","vuex","webpack3"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dave-wind.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-05-07T10:24:05.000Z","updated_at":"2024-11-22T08:20:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"9627647b-99af-44a8-b9c6-a76589543c87","html_url":"https://github.com/dave-wind/VPC","commit_stats":{"total_commits":36,"total_committers":2,"mean_commits":18.0,"dds":"0.11111111111111116","last_synced_commit":"87c9ec74728fb282366b1f004f012301cca1996f"},"previous_names":["dave-wind/vpc"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dave-wind%2FVPC","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dave-wind%2FVPC/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dave-wind%2FVPC/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dave-wind%2FVPC/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dave-wind","download_url":"https://codeload.github.com/dave-wind/VPC/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238553067,"owners_count":19491368,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["easymock","element-ui","flyio","vue-router","vuejs2","vuex","webpack3"],"created_at":"2024-09-24T13:53:52.169Z","updated_at":"2025-10-27T20:31:08.988Z","avatar_url":"https://github.com/dave-wind.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# VPC\n\n\u003e Vue permission Control\n\n## 项目描述\n\u003e 基于 vue 开发的一套统一登录 前端用户权限管理的后台系统\n\n## 项目地址\n* [dave-wind](https://dave-wind.github.io/VPC)\n\n## 构建\n\n``` bash\n# install node+git please\n\n# install dependencies\n$ npm install / cnpm install\n\n# serve with hot reload at localhost:8060\n$ npm run dev\n\n# build for production with minification\n$ npm run build\n\n```\n## 项目分析\n\u003e 基本思路\n#### 构思\n前端做权限控制，无非后台传数据 前端做判断 我看了大多数项目 都有角色的概念 前端在router.beforEach 导航守卫做文章\n但当我站在巨人肩旁眺望远方的时 总结觉得 前端与业务逻辑是需要解耦的 角色的概念都是人为提出的 其实前端只看数据\n那把权限就抽出来 就是数组 不同的身份角色 给前端不同的数组 再与本地 所有的路由做匹配 返回一个菜单 给用户展示\n\n#### 骨架\nvue-cli 初始化项目后 基于模块化 骨架组件构成：Login + Home Header Sidebar Home  业务内容放入 Hoem content内即可\n\n#### 登录\nVPC适用于多项目统一登录 在Login页面 登录成功 返回的有效token 在进行第二步操作 获取用户数据, 数据保存在vuex内\n考虑到刷新问题 因此 获取用户数据 就必须放在根组件 App.vue 内, 因为Vue是单向流思想 Login 作为App的子组件 需要在Login 登录成功后$emit 到App 执行callback 获取用户数据\n\n#### 接口mock\n上面说到数据 本项目采用 easy-mock mock数据 后端数据规定采用RestFul协议 mock了多种不同身份用户 登录成功返回200，token失效 401 登录成功 返回 token 通过 flyio 在header 添加token 切记这是第一次在Login页 添加 以后每次接口调用 都需 添加token 可在 flyio 拦截器里做\n\n\n#### 用户数据操作\n返回权限数组 在App页面 通过递归 fullPath 本地所有路由 操作 获取用户有效路由 保存在 Vuex内\n\n#### 页面展示\n在Sidebar for循环 vuex存储的有效路由并展示  Home组件展示路由具体内容\n\n\n## 设计构图\n\u003cimg alt=\"\" src=\"./screenshots/index.png\"/\u003e\n\n\n## 结构\n```\n│\n├─build\n│      build.js\n│      check-versions.js\n│      utils.js\n│      vue-loader.conf.js\n│      webpack.base.conf.js\n│      webpack.dev.conf.js\n│      webpack.prod.conf.js\n│\n├─config\n│      dev.env.js\n│      index.js\n│      prod.env.js\n│\n├─src\n│  │  404.vue\n│  │  App.vue                                // 根组件\n│  │  bus.js                                 // EventBus 适用于兄弟组件 通信\n│  │  dave.js                                // canvas 效果\n│  │  globar.js                              // webpack 全局注册ui组件\n│  │  main.js                                // 项目入口\n│  │  tools.js                               // 插件\n│  │\n│  ├─api\n│  │      axios.js\n│  │      common.js                          // 基本接口\n│  │      request.js                         // flyio 拦截器\n│  │      weather.js                         // 天气接口\n│  │\n│  ├─assets\n│  │  │  logo.png\n│  │  │\n│  │  └─theme-dave                            // 自定义主题\n│  │\n│  ├─components                               // 主要组件\n│  │  ├─common\n│  │  │      Header.vue\n│  │  │      Home.vue\n│  │  │      Login.vue\n│  │  │      SideBar.vue\n│  │  │\n│  │  ├─render                                 // render 渲染组件 适用多条件渲染\n│  │  │      btn-render.vue\n│  │  │\n│  │  ├─ui\n│  │  │      baseButton.vue                    // 基于element-ui btn ui组件 可层叠复用\n│  │  │\n│  │  └─view\n│  │          403.vue\n│  │          404.vue\n│  │          allocation.vue\n│  │          render.vue\n│  │          watch.vue\n│  │\n│  ├─router                                    // 本地所有路由\n│  │      fullPath.js\n│  │      index.js                             // 基本路由\n│  │\n│  └─store                                     // 状态管理 全局变量\n│          actions.js\n│          getters.js\n│          index.js\n│          mutations.js\n│          state.js\n│\n│  .babelrc\n│  .editorconfig\n│  .eslintignore\n│  .eslintrc.js                                 // 基于airbnb-base 个人配置的代码规则\n│  .gitignore\n│  .postcssrc.js\n│  index.html\n│  package-lock.json\n│  package.json\n│  README.md\n\n```\n## 项目模块\n\n#### login\n* 项目适用与多后台系统 统一登录 一个入口 登录接口就是正常的密码登录，返回token后 保存在 Authorization 内      \n* 在App.vue 也就是根组件 router-view 内 接受子组件$emit 后 执行login方法 调用接口统一获取 权限数据 在App内完成  \n\n```html\n \u003crouter-view @login=\"login\" @clearData=\"clearData\"\u003e\u003c/router-view\u003e\n```\n\n#### 统一清除函数\n\u003e 代码秉承一个入口一个出口的宗旨\n\n* 在header组件 logout执行后 清除token 刷新页面  \n* 因为我们在根组件App内 对有无token 会做判断 所以 logout 无需路由跳转  \n* 只要到login.vue 初始化时 就执行 clearData 清除所有数据    \n\n```js\nclearData () {\n if (this.$route.path === '/login') {\n     delete request.config.headers['Authorization'];\n     localStorage.removeItem('token');\n     this.$store.dispatch('CLEAR_STORE');\n }       \n}\n\n```\n\n#### token失效\nflyio 全局拦截响应 只要失效用户访问页面调用接口 失效状态码返回401 就跳转回login页面\n\n```js\nif (err.response.status === 401) {\n    window.location.href = '/#/login';\n  }\n```\n#### flyio \n* flyio 很棒 在浏览器 node 移动端 小程序 不同环境 都可以运用 VPC在 webpack.base.conf.js 有如下配置 import 引入才正确  \n* flyio 在小程序里 走的是 wx包模块详情可看官网或 mpvue-netBar  \n\n```js\nalias: {\n  'vue$': 'vue/dist/vue.esm.js',\n  '@': resolve('src'),\n  'flyio': 'flyio/dist/npm/fly'\n    }\n    \n```\n* flyio 亲测并没有 jsonp method 目前解决跨域 都是后端 在header头里设置 Access-Control-Allow-Origin: '*'  \n* 本项目 采用 ajax jsonp（是不是又回到写jquery的时代？jquery真的很强大呀！！）\n\n#### 组件注册\n\u003e webpack 神器啊 require.context\n* 通过 require.context 去读取指定路径下的组件 比如我们需要写很多公共的ui组件 但每次需要import 引入就很麻烦就用它吧  \n* 效果就是自动动态require组件 需要三参数 搜素的文件目录 是否搜素其子目录 以及配一个正则就完事了  \n\n\n## 打包优化\n* npm run build --report 可分析 dist包大小便于逐步击破 该死的文件  \n* config index.js productionSourceMap 以及 cssSourceMap 都改为 false 目的就是干掉 该死的map文件\n* npm install --save-dev compression-webpack-plugin 后 productionGzip 设置为true 开启亚索模式，呸 是压缩  也会减少体积 你不妨试试  \n* 异步组件 但实话告诉你们 其实异步组件 并不能 优化多少dist大小    \n* cdn 外部加载资源 webpack.base.conf.js 加上externals （虽然我tm每次都拼错）  \n```js\n externals: {\n    vue: 'Vue',\n    'element-ui': 'ElementUI',\n    nprogress: 'NProgress',\n    jquery: 'window.$'\n  }\n  \n```\n* 接着在 index内 加载 cdn 资源 切记 所有上externals的车的 代码内部不能写 Vue.use 不然cdn加载就是扯犊子 因为Vue.use 就是Vue写插件的 会挂载在Vue原型上  \n\n\n## 自动部署\n\u003e 详情可看 travis CI 官网\n注意:\n* webpack 配置 需要修改 在config index.js 内 build VPC 改为 assetsPublicPath: '' 而不是根目录 '/' 不然js会 404  \n* 具体 travis-CI 配置 结果不一样 详情可看官网 或 仿照VPC .travis.yml 配置\n \n\n\n## 技术分析\n\u003e Vue组件通信 使用分析\n\n\n1.Vuex：状态管理模式,集中式存储管理应用的所有组件的状态，并以相应的规则保证状态以一种可预测的方式发生变化\n2.EventBus: 非父子组件的通信 使用事件中心，允许组件自由交流\n案列重现：\n当我比如在该项目中Header组件里改变一个变量属性值 并要求在SideBar 和 Home组件里 响应其变化时候如何做？\n3.分析：\nVuex 顾名思义就是管理全局变量，这里是管理 而不是只读 是可读，可更改 可检测的，Vue是单向流 首先介绍一下ECMAScript俩种属性：\n数据属性和访问器属性，前者: [Configurable]，[[Enumerable],[Writable],[Value] 可配置 可枚举 可复写 value\n通常对象字面量创建 对象 var person = { name: \"dave\" } 就是数据属性 改变和读取的 只是 对象的 value\n而后者 访问器属性 [Configurable]]，[[Enumerable]],[[Get]],[[Set]，在JavaScript中我们使用Object.defineProperty来定义访问器属性\n在Vue里 获取 this.person 就是调用 get方法  设置就是 set方法。 Vue有自己的的 data tree 正是通过访问器属性才实现 依赖追踪 watch的\n除此 Vuex EventBus 之外 Vue.prototype.xx 以及 this.$root  和 本地存储 localStorage 操作组件变量都不具备watch功能\n\n4.总结：\nVue.prototype.xx，this.$root 只是可读取的 和更改的 在Vue的原型上修改读取 但并不能watch, Vue.prototype.xx 可以写全局变量 用来做 校验证 默认值 等操作\nlocalStorage 也是。它可以读取设置 有人说可以用addEventListener 监听storage 但是并不期望在Vue层这么做,本项目 token 就是用 本地存储\n综上所属  此案例就可以用到vuex  我们需要变量可预测 接着执行callback\n如果你觉得麻烦 就用EventBus 兄弟组件通信,$emit 触发 $on监听回调 即可\n\n\n## 事后一根烟\n本项目构建 重点不是需要丰富的后台组件 而是权限路由控制思想 只是搭建骨架\n给自己工作上做一总结 后期会多加封装组件化进项目之中，使\"项目\"更加充实健壮\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdave-wind%2Fvpc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdave-wind%2Fvpc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdave-wind%2Fvpc/lists"}