vue-element-admin:一个后台前端解决方案

官方文档

功能

- 登录 / 注销

- 权限验证
  - 页面权限
  - 指令权限
  - 权限配置
  - 二步登录

- 多环境发布
  - dev sit stage prod

- 全局功能
  - 国际化多语言
  - 多种动态换肤
  - 动态侧边栏(支持多级路由嵌套)
  - 动态面包屑
  - 快捷导航(标签页)
  - Svg Sprite 图标
  - 本地/后端 mock 数据
  - Screenfull全屏
  - 自适应收缩侧边栏

- 编辑器
  - 富文本
  - Markdown
  - JSON 等多格式

- Excel
  - 导出excel
  - 导入excel
  - 前端可视化excel
  - 导出zip

- 表格
  - 动态表格
  - 拖拽表格
  - 内联编辑

- 错误页面
  - 401
  - 404

- 組件
  - 头像上传
  - 返回顶部
  - 拖拽Dialog
  - 拖拽Select
  - 拖拽看板
  - 列表拖拽
  - SplitPane
  - Dropzone
  - Sticky
  - CountTo

- 综合实例
- 错误日志
- Dashboard
- 引导页
- ECharts 图表
- Clipboard(剪贴复制)
- Markdown2html

前序准备

项目技术栈基于 ES2015+vuevuexvue-routervue-cliaxioselement-ui,所有的请求数据都使用Mock.js进行模拟。

项目代码

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                  # 全局公用方法
│   ├── vendor                 # 公用vendor
│   ├── 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

开发:

工具安装:npm包管理工具,git 代码管理

   # 克隆项目
   `git clone https://github.com/PanJiaChen/vue-element-admin.git`
   # 进入项目目录
   `cd vue-element-admin`
   # 安装依赖
   `npm install`
   # 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。
   # 可以通过如下淘宝镜像解决 npm 下载速度慢的问题
   `npm install --registry=https://registry.npm.taobao.org`
   # 项目运行
   `npm run dev`

浏览器访问 http://localhost:9527

若出现node-sass安装错误,项目根目录新建文件.npmrc,并添加如下代码后重新安装。

sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
registry=https://registry.npm.taobao.org

路由和侧边栏

本项目侧边栏和路由是绑定在一起的,所以你只有在 @/router/index.js 下面配置对应的路由,侧边栏就能动态的生成了。

配置项

//当设置 true 的时候该路由不会在侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1
hidden: true // (默认 false)

//当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
redirect: 'noRedirect'

//当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
//只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面
//若你想不管路由下面的 children 声明的个数都显示你的根路由
//你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由
alwaysShow: true

name: 'router-name' //设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题
meta: {
  roles: ['admin', 'editor'] //设置该路由进入的权限,支持多个权限叠加
  title: 'title' //设置该路由在侧边栏和面包屑中展示的名字
  icon: 'svg-name' //设置该路由的图标
  noCache: true //如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
  breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示
}
示例:
{
  path: '/permission',
  component: Layout,
  redirect: '/permission/index', //重定向地址,在面包屑中点击会重定向去的地址
  hidden: true, // 不在侧边栏线上
  alwaysShow: true, //一直显示根路由
  meta: { roles: ['admin','editor'] }, //你可以在根路由设置权限,这样它下面所以的子路由都继承了这个权限
  children: [{
    path: 'index',
    component: ()=>import('permission/index'),
    name: 'permission',
    meta: {
      title: 'permission',
      icon: 'lock', //图标
      role: ['admin','editor'], //或者你可以给每一个子路由设置自己的权限
      noCache: true // 不会被 <keep-alive> 缓存
    }
  }]
}

路由

这里的路由分为两种,constantRoutesasyncRoutes
constantRoutes: 代表那些不需要动态判断权限的路由,如登录页、404、等通用页面。
asyncRoutes: 代表那些需求动态判断权限并通过 addRoutes 动态添加的页面。

侧边栏

代码地址:@/views/layout/components/Sidebar

  • 侧边栏有两种形式:submenu 和 直接 el-menu-item。 一个是嵌套子菜单,另一个则是直接一个链接。
    • 当你一个路由下面的 children 声明的路由大于>1 个时,自动会变成嵌套的模式。
    • 如果子路由正好等于一个就会默认将子路由作为根路由显示在侧边栏中。若不想这样,可以通过设置在根路由中设置 alwaysShow: true 来取消这一特性。
  • 所有的 css 都可以在 @/styles/sidebar.scss 中找到,可以根据自己的需求进行修改。
  • unique-opened
    你可以在Sidebar/index.vue中设置unique-opened来控制侧边栏,是否只保持一个子菜单的展开。

多级目录(嵌套路由)

如果路由是多级目录,如本项目 @/views/nested 那样, 有三级路由嵌套的情况下,不要忘记还要手动在二级目录的根文件下添加一个 <router-view>
如:@/views/nested/menu1/index.vue,原则上有多少级路由嵌套就需要多少个<router-view>

点击侧边栏 刷新当前路由

  • 方法1:监听侧边栏每个 link 的 click 事件
clickLink(path) {
  this.$router.push({
    path,
    query: {
      t: +new Date() //保证每次点击路由的query项都是不一样的,确保会重新刷新view
    }
  })
}

ps:不要忘了在 router-view 加上一个特定唯一的 key,如 <router-view :key="$route.path"></router-view>, 但这也有一个弊端就是 url 后面有一个很难看的 query 后缀如 xxx.com/article/list?t=1496832345025

  • 方法2:判断当前点击的菜单路由和当前的路由是否一致,一致的时候,会先跳转到一个专门 Redirect 的页面,它会将路由重定向到我想去的页面,这样就起到了刷新的效果了。

点击的时候重定向页面至 /redirect

const { fullPath } = this.$route
this.$router.replace({
  path: '/redirect' + fullPath
})

redirect 页面在重定向回原始页面

// redirect.vue
// https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/redirect/index.vue
export default {
  beforeCreate() {
    const { params, query } = this.$route
    const { path } = params
    this.$router.replace({ path: '/' + path, query })
  },
  render: function(h) {
    return h() // avoid warning message
  }
}

内容模块:

页面整体结构

@ 是 webpack 的 alias 配置,对应本项目vue.config.js > configureWebpack > alias配置。

布局: @/layout

对应上图页面整体结构,可根据需求自行修改样式

内容区:@/layout/components/AppMain
  • <transition>标签是定义了页面之间切换动画,可在transition.scss文件中添加修改动画;
  • <keep-alive>标签主要是为了缓存 <router-view>路由,配合页面的 tabs-view 标签导航使用,如不需要可删除。
  • <router-view>子页面渲染处,根据路由children下配置

新增页面步骤:

  1. 新增路由
{
  path: '/excel',
  component: Layout,
  redirect: '/excel/export-excel',
  name: 'excel',
  meta: {
    title: 'excel',
    icon: 'excel'
  },
  children: [
    {
      path: 'export-excel',
      component: ()=>import('excel/exportExcel'),
      name: 'exportExcel',
      meta: { title: 'exportExcel' }
    }
  ]
}
  1. 新增View

在 @/views 文件下 创建对应的文件夹,一般一个路由对应一个文件,该模块下的功能组件或者方法就建议在本文件夹下创建一个 utilscomponents 文件夹,各个功能模块维护自己的 utilscomponents 组件。

  1. 新增api

@/api

  1. 新增组件

@/components:公共组件

  1. 新增样式

@/style:全局样式,加 scoped 可防止样式全局污染

  • 自定义 element-ui 样式
.article-page {
  /* 你的命名空间 */
  .el-tag {
    /* element-ui 元素*/
    margin-right: 0px;
  }
}
  • 父组件改变子组件样式 深度选择器
<style scoped>
.a >>> .b { /* ... */ }
</style>

总结:不管组件还是样式,公共放外部,私有放内部,方便维护

Postcss

新版的 vue-cli webpack 模板 init 之后根目录下默认有一个postcss.config.js。vue-loader 的 postcss 会默认读取这个文件的里的配置项,所以在这里直接改配置文件就可以了。配置和 postcss是一样的。

// postcss.config.js
module.exports = {
  plugins: {
    autoprefixer: {}
  }
}

// package.json
"browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]

如上面代码所述的,autoprefixer 会去读取 package.json 下 browserslist 的配置参数

  • > 1% 兼容全球使用率大于 1%的浏览器
  • last 2 versions 兼容每个浏览器的最近两个版本
  • not ie <= 8 不兼容 ie8 及以下

具体可见 browserslist

Mixin

本项目没有设置自动注入 sass 的 mixin 到全局,所以需要在使用的地方手动引入 mixin

<style rel="stylesheet/scss" lang="scss">
  @import "src/styles/mixin.scss";
</style>

如需要自动将 mixin 注入到全局 ,可以使用sass-resources-loader

和服务端进行交互

前端请求流程

在 vue-element-admin 中,一个完整的前端 UI 交互到服务端处理流程是这样的:

  1. UI 组件交互操作;
  2. 调用统一管理的 api service 请求函数;
  3. 使用封装的 request.js 发送请求;
  4. 获取服务端返回;
  5. 更新 data;

为了方便管理维护,统一的请求处理都放在 @/src/api 文件夹中,并且一般按照 model 纬度进行拆分文件

api/
  login.js
  article.js
  remoteSearch.js
  ...
request.js

@/src/utils/request.js 是基于 axios 的封装,便于统一处理 POST,GET 等请求参数,请求头,以及错误提示信息等。具体可以参看 request.js。 它封装了全局 request拦截器response拦截器统一的错误处理统一做了超时处理baseURL设置等

一个请求文章列表页的例子:

// api/article.js
import request from '../utils/request';
export function fetchList(query) {
  return request({
    url: '/article/list',
    method: 'get',
    params: query
  })
}


// views/example/list
import { fetchList } from '@/api/article'
export default {
  data() {
    list: null,
    listLoading: true
  },
  methods: {
    fetchData() {
      this.listLoading = true
      fetchList().then(response => {
        this.list = response.data.items
        this.listLoading = false
      })
    }
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335