• 从0开始搭建vue2管理后台基础模板


    网站主要完成:侧边菜单栏、页面标签卡、内容栏
    源代码gitee地址:https://gitee.com/zhao_liangliang1997/navigation-bar

    一、起步

    1、创建vue项目

    vue create 项目名
    
    • 1

    2、引入element

    3、其他安装

    1、首先需要安装如下

    cnpm install vuex
    cnpm install vue-router
    cnpm install sass
    cnpm install sass-loader
    cnpm install node -sass
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、main.js中引入相关

    引入后,可能会报错,请别急,继续往下走。

    import Vue from 'vue'
    import App from './App.vue'
    import store from './store'
    import router from './router'
    import ElementUI from 'element-ui';
    import 'element-ui/lib/theme-chalk/index.css';
    // 引入基础样式[下面给链接复制style.scss以及variables.scss]
    import './assets/scss/style.scss';
    
    Vue.config.productionTip = false
    Vue.use(ElementUI);
    
    new Vue({
        router,
        store,
        render: h => h(App)
    }).$mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3、改造App.vue

    <template>
      <div id="app">
          <router-view/>
      </div>
    </template>
    <script>
    export default {
      name: 'App',
    }
    </script>
    <style lang="scss">
    #app {
        height: 100vh;
    }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    完成侧边栏的项目结构,如下图:

    在这里插入图片描述

    相关链接

    1、style.scss;
    2、variables.scss

    4、配置路由[router下的index.js]

    配置如下路由后,下一步您需要对layout进行页面设计【第一步侧边菜单栏】

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    
    Vue.use(VueRouter)
    
    const router = new VueRouter({
        routes:[
            {
                path: '/',
                hidden: true,
                component: () =>
                    import ('@/page/layout'),
                children: [
                    {
                        path: 'index',
                        component: () =>
                            import ('@/page/index'),
                        hidden: true
                    }
                ]
            },
        ]
    })
    export default router
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    二、侧边菜单栏的设计

    1、封装菜单组件navMenu.vue

    <template>
        <div>
            <template v-for="(item, index) in userNav">
                <el-menu-item :index="item.path" v-if="!item.hidden && !item.children">
                    {{ item.name }}
                </el-menu-item>
                <el-submenu :index="item.path" v-if="!item.hidden && item.children">
                    <template slot="title">{{ item.name }}</template>
                    <nav-menu :user-nav="item.children"/>
                </el-submenu>
            </template>
        </div>
    </template>
    <script>
    export default {
        name: "navMenu",
        props: {
            userNav: {
                type: Array,
                default: []
            }
        }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    2、layout中实现侧边栏
    思路: ①首先画出侧边栏;②路由信息存放vuex中;③vuex中的路由从路由js中获取

    <template>
        <el-container>
            <el-aside width="20vh" class="aside">
                <div class="logo_box pr">
                    <span class="fl w_100 tc f20 text-white w_h_center pl20 pr20">测试服务平台</span>
                </div>
                <el-menu :default-active="activeIndex"
                         class="el-menu-vertical-demo"
                         style="flex: 1; overflow: auto; width: 100%; overflow-x: hidden"
                         background-color="#6187F7"
                         text-color="#fff"
                         active-text-color="#ffd04b"
                         unique-opened
                         @select="handleSelect">
                    <template v-for="(item, index) in userNav">
                        <el-menu-item :key="index" :index="item.path" v-if="!item.hidden && !item.children">
                            {{ item.name }}
                        </el-menu-item>
                        <el-submenu :key="index" :index="item.path" v-if="!item.hidden && item.children">
                            <template slot="title">{{ item.name }}</template>
                            <nav-menu :user-nav="item.children"/>
                        </el-submenu>
                    </template>
                </el-menu>
            </el-aside>
            <el-container>
                <el-header>Header</el-header>
                <el-main>
                    <router-view/>
                </el-main>
            </el-container>
        </el-container>
    </template>
    
    <script>
    import NavMenu from '@/page/navMenu/navMenu'
    import {mapState, mapMutations} from 'vuex'
    export default {
        name: "VueLayout",
        components: {
            NavMenu
        },
        data() {
            return {
                url: '',
                activeIndex:'/'
            }
        },
        created() {
            // 获取菜单权限 [因此刻未配动态路由,所以在此处调用]
            this.setMenu()
        },
        computed: {
            ...mapState(['userNav'])
        },
        methods: {
            ...mapMutations(['setMenu']),
            handleSelect: function (key) {
                let path = this.$route.path
                if (path !== key) {
                    if (key === '/' && path === '/index') {
                        return
                    }
                    this.$router.push(key)
                }
            },
        }
    }
    </script>
    
    <style less scoped>
    /deep/ .el-tabs__header {
        margin: 0;
    }
    .aside {
        background-color: #6187F7;
        display: flex;
        flex-direction: column;
    }
    .logo_box {
        height: 60px;
        border-bottom: 1px solid white;
    }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84

    3、vuex

    //1.引入Vue
    import Vue from 'vue';
    import Vuex from 'vuex';
    import view from '@/router/baseView';
    import router from '@/router/index'
    import dynamicView from "@/router/dynamicView";
    //2.安装
    Vue.use(Vuex);
    const store = new Vuex.Store({
        //存储状态
        state:{
            userNav: [],    // 导航栏路由, 默认未登录,展示静态路由
            activeIndex: '/',
            tagMap: new Map(),
        },
        // Vuex中的Store状态(state)更新的唯一方式:提交Mutation
        mutations:{//定义mutations
            // 定义改变全局共享数据的方法
            setMenu(state) {
                let baseView = Object.assign([], view) // 初始化导航栏
                // 根据菜单权限获取菜单
                let nav = getNav(dynamicView)
                nav.forEach(item => {
                    baseView.push(item)
                })
                state.userNav = baseView
            },
        }
    })
    //导出
    export default store
    
    function getNav(navs) {
        let list = []
        navs.forEach(nav => {
            let obj = {}
            obj.path = nav.path
            obj.name = nav.name
            obj.icon = nav.icon
            obj.isPage = nav.isPage
            if (nav.isPage) {
                obj.component = () => import ('@/views' + nav.path)
            }
            if (nav.children) {
                obj.children = getNav(nav.children)
            }
            list.push(obj)
        })
        return list
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    三、页面标签卡

    1、头部、内容栏及页面标签卡

    页面标签卡:标签卡为外部引入组件【代码请到Gitee查看】

    在这里插入图片描述

    2、注意事项:

    1、tag改变方法【activeIndex从vuex引入】
    2、tag标签页根据路由创建【navClick从vuex引入】
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    3、最终效果

    在这里插入图片描述

    4、后续相关token

    1.客户端使用用户名跟密码请求登录
    2.服务端收到请求,去验证用户名与密码
    3.验证成功后,服务端会签发一个 token 并把这个 token 发送给客户端
    4.客户端收到 token 以后,会把它存储起来,比如放在 cookie 里或者 localStorage 里
    5.客户端每次向服务端请求资源的时候需要带着服务端签发的 token
    6.服务端收到请求,然后去验证客户端请求里面带着的 token ,如果验证成功,就向客户端返回请求的数据
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 每一次请求都需要携带 token,需要把 token 放到 HTTP 的 Header 里

    • 基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token 数据。用解析 token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库

    • token 完全由应用管理,所以它可以避开同源策略

    • 什么是同源策略?
      同源策略是客户端脚本(尤其是 Javascript)的重要的安全度量标准。其目的是防止某个文档或脚本从多个不同源装载。 这里的同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议,指一段脚本只能读取来自同一来源的窗口和文档的属性。

    • 为什么要有同源限制?
      我们举例说明:比如一个黑客程序,他利用 Iframe 把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过 Javascript 读取到你的表单中 input 中的内容,这样用户名,密码就轻松到手了

    5、permission.js

    在登陆这个流程中,permission.js这个是很最重要的一环,是路由的全局钩子(beforeEach和afterEach),全局钩子就是每次跳转的时候可以根据情况进行拦截,不让它进行跳转。使用场景最常见的就是有些页面需要用户登陆之后才能访问,就可以在beforeEach中校验用户是否登陆来进行相对应的拦截处理。

    6、相关学习博客推荐:

    vue-element-admin 登陆

  • 相关阅读:
    Mac | Vmware Fusion | 分辨率自动还原问题解决
    文件操作和IO
    warning LNK4017: DESCRIPTION 语句不支持目标平台;已忽略
    认识并安装WSL
    独立IP主机怎么样?对网站有什么影响
    Springboot中国古代史在线学习网站毕业设计源码260839
    与二值化阈值处理相关的OpenCV函数、方法汇总,便于对比和拿来使用
    SpringCloud-Sleuth
    ✔ ★【备战实习(面经+项目+算法)】 10.22学习时间表(总计学习时间:4.5h)(算法刷题:7道)
    JavaWeb课程设计-学生信息管理系统(Jsp+Servlet+MySql)
  • 原文地址:https://blog.csdn.net/javaScript1997/article/details/127956470