vue-admin-后台管理系统,全文注释。

# vue-admin-stepbystep

> A Vue.js project
### 项目背景
这是公司的一个项目的阉割版,可以用作模板,里面的技术点基本全部都有注释,全都有注释,全都有注释,重要事说三遍,
写注释很辛苦,给个小赞,github给个小start,鼓励鼓励码字的我,项目正在陆续的完善中。还有重申一点,我们是前端工程师,不是码农。


麻雀虽小五脏俱全:[项目地址 https://github.com/whylisa/vue-admin-stepbystep)

## 项目功能
- 1 登录
- 2 首页
- 3 退出
- 4 table页

## 项目技术点
- 1,使用vue
- 2,使用echarts 
- 3, 使用json-server (系列二写详细文档)
- 4, 使用node起一个简单的服务,服务于接口(系列二写详细文档)
- 5, 使用axios
- 6, vue-router的使用规则(异步加载,和同步加载)
- 7, 回话拦截的使用(localstorage or cookie)
- 8, 配合element-UI 
- 9, 修改组件里面的样式里面的坑
- 10, 打包时的优化
- 11, DNS优化
- 12, 配置本地代理,使用接口(系列二写详细文档)
- 13, 使用axios配合json-server 模拟增删改查(系列二写详细文档)
- 14, 使用nprogress 插件
- 15, 鲜为人知的element-UI 的滚动条
- 16, 栅格布局,大小屏适应配合媒体查询
- 17, css使用less 
- 18, 代码风格,个人风格,禁用了jslint 防止不懂得小伙伴抓狂
- 19, 兼容性的处理(系列二写详细文档)
## 项目搭建

- 1 `vue init webpack XX` 使用vue-cli 2.0

```html
Project name                            :默认
Project description                     :默认
Author                                  :默认
Vue build                               :选择 Runtime + Compiler
Install vue-router?                     :Y
Use ESLint to lint your code?           :Y 选择 Standard
Set up unit tests                       :n
Setup e2e tests with Nightwatch?        : n
Should we run `npm install` for you after the project has been created? (recommended) : Yes, use NPM
```

- 2 进入项目:cd vue-admin-stepbystep
- 3 运行项目:npm run dev

## 如何添加一个新的功能???

- 1 在 `components` 中新建一个文件夹(login),在文件中创建组件(Login.vue)
- 2 在 `router/index.js` 中导入组件(login.vue)
- 3 配置路由规则

## 在项目中使用 element-ui(其他自行gg加深映像)

- [ElementUI 文档](http://element-cn.eleme.io/#/zh-CN/component/installation)
- 安装:`npm i element-ui -S`

```js
// main.js

// 导入elementui - js
import ElementUI from 'element-ui'
// 导入elementui - css
import 'element-ui/lib/theme-chalk/index.css'
// 安装插件
Vue.use(ElementUI)
```

---

## 项目启动做了什么

- 1 在终端中运行:`npm run dev`,实际上就是运行了:`webpack-dev-server ...`
- 2 使用 webpack-dev-server 开启一个服务器
- 3 根据指定的入口 `src/main.js` 开始分析入口中使用到的模块
- 4 当遇到 `import` 的时候,webpack 就会加载这些模块内容(如果有重复模块,比如:Vue,实际上将来只会加载一次),遇到代码就执行这些代码
- 5 创建 Vue 实例,将 App 组件作为模板进行编译,并且将 App 组件中 template 的内容渲染在页面 #app 的位置

## 路由配置
- 1 异步加载路由
- 2 使用进度条插件
- 3 登录拦截 会话保持
```js
import Vue from 'vue'
import Router from 'vue-router'
//引入nprogress进度条
import NProgress from 'nprogress'
//引入nprogress进度条的样式
import 'nprogress/nprogress.css'
//在打包过程中每一个组件都会打包成一个js文件,如果不使用使用/* webpackChunkName: "home" */
//在打包的时候就会生成0.js,1.js等等,使用了之后就会打包成home.js
// 导入 Login 组件(注意,不要添加 .vue 后缀)
//这是路由的异步加载,!important,这是优化项目必须的

//引入home组件
const Home = () => import(/* webpackChunkName: "home" */ '@/components/home')
//引入登录组件
const Login = () => import(/* webpackChunkName: "home" */ '@/components/login')
//引入table组件
const Table = () => import(/* webpackChunkName: "home" */ '@/components/table/table')
//引入homeMain组件
const HomeMain = () => import('@/components/HomeMain')

//这里是同步加载
//import Login from '@/components/login/Login'

Vue.use(Router)

const router = new Router({
    mode: 'history',//开启了history模式,去除了#,
     // 在vue中,一般来说通过实例去访问某个属性的
     // vm.xxxx  vm.$set  vm.$refs  vm.$router
    routes: [
        {
            path: '/',
            redirect: '/homeMain'//路由的重定向
        },
        {
            path: '/login',
            name: 'login',
            component: Login
        },
        {
            path: '/home',
            name: 'home',
            component: Home,
            // children 用来配置子路由,将来匹配的组件会展示在 Home 组件的 router-view 中
            // 对于子路由path来说:
            // 1 如果不是以 / 开头,那么,哈希值为: 父级path + / + 子级path
            //    也就是: /home/homeMain
            // 2 如果子级路由的path是以 / 开头的,那么将来的哈希值为:/users 不再带有父级的path了
            //    也就是:/homeMain
            //这是页面中的子路由,在页面中必须声明router-view作为出口
            children: [
                {
                    path: '/homeMain',
                    name: 'homeMain',
                    component: HomeMain
                },
                {
                    path: '/table',
                    name: 'table',
                    component:Table
                }
            ]
        }
    ]
});
// 给router配置导航守卫
// to: 去哪儿
// from: from 哪儿来
// next() :  next():放行   next('/login') 去login组件
// 在登录成功以后,将 token 存储到 localStorage 中
// 在 导航守卫 中先判断当前访问的页面是不是登录页面
// 如果是登录页面,直接放行(next())
// 如果不是登录页面,就从 localStorage 中获取 token,判断有没有登录
// 如果登录了,直接放行(next())
// 如果没有登录,就跳转到登录页面让用户登录(next('/login')
router.beforeEach((to, from, next) => {
//    开启进度条
    NProgress.start()
//    获取是否有token
    let token = localStorage.getItem('myToken')
    // 如果已经就是要去login了,就不需要拦截了
    if (to.path === '/login' || token) {
        next()
    }else {
        next('/login')
    }
    
});
router.afterEach(() => {
//    关闭进度条
    NProgress.done()
})

export default router
```
## 登录功能

- 1 安装:`npm i -S axios`
- 2 在 `Login.vue` 组件中导入 axios
- 3 使用 axios 根据接口文档来发送请求,完成登录
- 4 登录时设置token ,可以用localStorage cookie等任君选择
 ```html
 


            

                
                
                    
                        
                        
                        
                        
                        
                            
                                
                            

                            
                                
                                
                                

                                
                            
                            
                                
                                登录
                                重置
                            

                        
                    
                    长得很帅
                
            


            
        

    

 ```
```js
 export default {
        data () {
            return {
//                定义一些变量,可以使用{{}}语法在页面中直接获取
                activeName: 'first',
                form: {
                    username: 'why',
                    password: "123456"
                },
                rules: {
                    // 用户名的校验
                    username: [
                        // 用户名是必须
//                        required是否必须
//                        message提示信息
//                        trigger如何触发
                        { required: true, message: '请输入用户名', trigger: 'change' },
                        { min: 3, max: 6, message: '长度在 3 到 6 个字符', trigger: 'change' }
                    ],
                    // 密码的校验
                    password: [
                        { required: true, message: '请输入密码', trigger: 'change' },
                        { min: 6, max: 12, message: '长度在 6 到 12 个字符', trigger: 'change' }
                    ]
                }
            }
        },
        methods: {
            login () {
//             先触发页面中的检验规则,不通过给提示,通过就向后台发送请求,
//           $refs是vue中获取页面的,在html中要写 ref="form"
             this.$refs.form.validate(async (valid) => {
                 if (valid) {
//                     使用axios向后台发送请求
//                  在es6中的箭头函数没有this绑定,可以打印出来指向的是vue实例,这点可以自行百度,加深映像
                     this.axios('/api/login').then( res => {
                         console.log(res.data[0])//用来查看接口里面的数据
                         let lg = res.data[0] //把数据赋值给变量
                         console.log(lg.username,lg.password)//主要用来查看数据
                         if(lg.username === this.form.username && lg.password==this.form.password){
                             localStorage.setItem('myToken',lg.username)//设置拦截,可以用cookie等,在控制台中的Application中查看
                             this.$message.success('恭喜你,登录成功')//登录成功的提示
                             this.$router.push('homeMain') //使用编程式导航路由进行跳转
                         }else {
                             this.$message.error('账号或者密码错误')//账号密码错误时的提示

                         }
                     })
                 }
             })
            },
            reset () {
                this.$refs.form.resetFields()//清空输入框中的信息
//                数据被我写死了,可以自行改动
            }
        }
  };
```
## 顶部和侧边
```html

            
            
                


                

                    

                        
                        退出
                    

                    

                        
                        
                        张三
                    

                    

                        
                        联系我们
                    

                

            
            
                
                    
                          
                          
                          
                          
                          
                          
                          
                          
                          
                        
                            
                                
                            

                        
                            
                                
                                
                                    table
                                

                            

                        

                    

                

                
                    
                    
                    
                        
                            
                            
                          
                          

                        

                      
                      
                      

                    

                    

                

            

        
```
```js
export default {
        created() {

        },
        data() {
            return {

            }
        },
        methods: {
            gomain() {
            //编程式导航
                this.$router.push('/homeMain')
            },
          //退出功能
            layout() {
//                退出功能要移除localStorage中的myToken
                localStorage.removeItem('myToken')
//                跳转到首页
                this.$router.push('login')
//                退出成功提示
                this.$message.success('退出成功了')
            },
            
        },
    }
```
## 首页
- 代码有点多截取一点,主要对echarts做了修改,x轴箭头呀,修改柱状图的样式呀等,还有element的栅格布局配合媒体查询
```js 
xAxis: {
       data: ["三月", "四月", "五月", "六月", "七月"],
        axisLine: {
            symbol: ['none', 'arrow'],
            lineStyle: {
            color: 'rgba(212,212,212,1)', // x坐标轴的轴线颜色 
                width: 1 //这里是坐标轴的宽度,为0就是不显示 
                }
                    }
            },
            yAxis: [{

            type: 'value',
            axisLabel: {
                show: false //这行代码控制着坐标轴x轴的文字是否显示 
            },
            splitLine: {
                show: false, // 网格线是否显示 
                // 改变样式 
            lineStyle: {
                color: '#EDEDED' // 修改网格线颜色 
                    }
            },
            axisLine: {
                lineStyle: {
                color: '#fff', // x坐标轴的轴线颜色 
                width: 0 //这里是坐标轴的宽度,为0就是不显示 
                    }
                }
        }],
```
## 表格的使用
```html


        

            
            
            
            
            查询
        

        

            
                
                
                
                
                
                
                
                
                
                 
                           :data="tableData"
              style="width: 100%"
              :header-cell-style="{background:'red'}"
              >
                               prop="date"
                label="日期"
                align="center"
                width="180">
              
                               prop="name"
                label="姓名"
                align="center"
                width="180">
              
              
                               prop="address"
                align="center"
                label="地址">
              
            
        

    

```
```js 
export default {
      data() {
        return {
//          绑定的input 查询关键字
          query: '',
//          需要一个数组用来存放table的数据
//          这是element组件里面的,
            tableData: []
        }
      },
      mounted() {
//          在vue的生命周期的mounted中调用渲染列表
          this.initTable()
      },
      methods:{
          initTable() {
              this.axios('/api/table').then( res => {
                  console.log(res.data)//查看接口返回时什么样的数据,要常用
                  this.tableData = res.data //接口返回的是一个数组,直接可以赋值给table
              })
          },
          search() {
              
          }
      }
    }
```
## 改element-ui的样式注意!
```html