zoukankan      html  css  js  c++  java
  • SpringBoot + Vue + ElementUI 实现后台管理系统模板 -- 前端篇(二):引入 element-ui 定义基本页面显示

    前提:

    (1) 相关博文地址:

     SpringBoot + Vue + ElementUI 实现后台管理系统模板 -- 前端篇(一):搭建基本环境:https://www.cnblogs.com/l-y-h/p/12930895.html

    (2)代码地址:

    https://github.com/lyh-man/admin-vue-template.git

    一、定义公共组件页面

      简单的页面效果如下所示:(做的比较粗糙,大致理解页面即可)

    1、安装 element-ui

    (1)简介
      一款 ui 框架。使用 element-ui 用于实现页面的绘制。

    【官网:】
        https://element.eleme.cn/#/zh-CN
        
    【文档:】
        https://element.eleme.cn/#/zh-CN/component/installation

    (2)安装
      可以通过 npm 或者 cdn 方式使用,此处使用 npm 方式安装。

    【安装方式一:(npm 安装)】
        npm install element-ui
        
    【安装方式二:(CDN 方式引入)】
        <!-- 引入样式 -->
        <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
        <!-- 引入组件库 -->
        <script src="https://unpkg.com/element-ui/lib/index.js"></script> 

    (3)引入 element-ui
      在 main.js 中引入(也可以自定义一个 js,然后在 main.js 中引入自定义的 js)。

    // 引入 element-ui
    import ElementUI from 'element-ui'
    // 引入 element-ui 的 css 文件
    import 'element-ui/lib/theme-chalk/index.css';
    // 声明使用 element-ui
    Vue.use(ElementUI);

    2、修改 App.vue

    (1)简介
      页面主入口。
      通过 router 将组件 显示在 router-view 标签处。(基本路由规则到本文末尾可以看)

    (2)修改页面内容

    <template>
      <div id="app">
        <router-view/>
      </div>
    </template>
    
    <style>
    #app {
      font-family: Avenir, Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
    }
    /* 解决子组件中 height: 100% 不生效问题 */
    html,body,#app{
        height: 100%;
        margin: 0;
        padding: 0;
        overflow: hidden;
    }
    </style>

    3、404.vue

    (1)简介
      定义错误页面。
      当错误发生时,用于跳转到 404 页面。

    (2)定义页面内容

    <template>
        <div class="error-wrapper">
            <h2 class="not-found-title">404</h2>
            <p class="not-found-desc">抱歉!您访问的页面<em>失联</em>啦 ...</p>
            <el-button @click="$router.go(-1)">返回上一页</el-button>
            <el-button type="primary" class="not-found-btn-gohome" @click="$router.push({ name: 'Home' })">进入首页</el-button>
        </div>
    </template>
    
    <script>
        export default {}
    </script>
    
    <style>
        .error-wrapper {
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
            overflow: hidden;
        }
    
        .not-found-title {
            margin: 20px 0 15px;
            font-size: 10em;
            font-weight: 400;
            color: rgb(55, 71, 79);
        }
    
        .not-found-desc {
            margin: 0 0 30px;
            font-size: 26px;
            color: rgb(118, 131, 143);
        }
    
        .not-found-desc>em {
            font-style: normal;
            color: #ee8145;
        }
    
        .not-found-btn-gohome {
            margin-left: 30px;
        }
    </style>

    (3)页面显示如下:

    4、Login.vue

    (1)简介
      定义登陆页面。
      访问系统时,用于跳转到登录界面。

    背景图(来源于网络):

    (2)定义页面内容:

    <template>
        <div class="login-wrapper">
            <div class="login-content">
                <div class="login-main">
                    <h2 class="login-main-title">管理员登录</h2>
                    <el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" status-icon>
                        <el-form-item prop="userName">
                            <el-input v-model="dataForm.userName" placeholder="帐号"></el-input>
                        </el-form-item>
                        <el-form-item prop="password">
                            <el-input v-model="dataForm.password" type="password" placeholder="密码"></el-input>
                        </el-form-item>
                        <el-form-item>
                            <el-button class="login-btn-submit" type="primary" @click="dataFormSubmit()">登录</el-button>
                        </el-form-item>
                    </el-form>
                </div>
            </div>
        </div>
    </template>
    <script>
        export default {
            data() {
                return {
                    dataForm: {
                        userName: '',
                        password: ''
                    },
                    dataRule: {
                        userName: [{
                            required: true,
                            message: '帐号不能为空',
                            trigger: 'blur'
                        }],
                        password: [{
                            required: true,
                            message: '密码不能为空',
                            trigger: 'blur'
                        }]
                    }
                }
            },
            methods: {
                // 提交表单
                dataFormSubmit() {
                    // TODO:登录代码逻辑待完善
                    alert("登录代码逻辑未完善")
                    this.$router.replace({name: 'Home'})
                }
            }
        }
    </script>
    <style>
        .login-wrapper {
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
            overflow: hidden;
            background-color: rgba(38, 50, 56, .6);
            background: url(~@/assets/login_bg.jpg) no-repeat;
            background-size: 100% 100%;
        }
    
        .login-content {
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
            margin: auto;
            height: 300px;
             400px;
            background-color: #112234;
            opacity: .8;
        }
    
        .login-main {
            color: beige;
            padding: 20px 20px 10px 20px;
        }
    </style>

    (3)页面显示如下:

    二、定义主页面

      主页面 可以拆分成多个组件,每个组件负责一部分页面的显示。
      拆分成 Header、Aside、Content 三个页面。
    其中:
      Header          用于定义导航栏信息
      Aside             用于定义菜单栏信息
      Content         用于显示各个菜单选项的页面

    1、Home.vue

    (1)简介
      定义主界面。
      通过 Login 登录系统后,需要跳转到 主页面。

    (2)定义页面内容

    <template>
        <!-- 
            v-loading、element-loading-text、element-loading-background、element-loading-spinner 用于定义加载的样式
         -->
        <el-container class="container" v-loading="false" element-loading-text="拼命加载中" element-loading-background="rgba(0, 0, 0, 0.8)"
         element-loading-spinner="el-icon-loading">
            <!-- 侧边栏 -->
            <Aside :foldAside="foldAside" />
            <!-- 
                direction="vertical"  用于垂直布局
            -->
            <el-container direction="vertical">
                <!-- 头部导航栏 -->
                <Header @foldOrOpenAside="foldOrOpen" />
                <!-- 内容 -->
                <Content />
            </el-container>
        </el-container>
    </template>
    
    <script>
        import Header from '@/views/home/Header.vue'
        import Aside from '@/views/home/Aside.vue'
        import Content from '@/views/home/Content.vue'
    
        export default {
            name: 'Home',
            components: {
                Header,
                Aside,
                Content
            },
            data() {
                return {
                    foldAside: true
                }
            },
            methods: {
                foldOrOpen(data) {
                    this.foldAside = data
                }
            }
        }
    </script>
    <style>
        .container {
            height: 100%;
        }
    </style>

    (3)页面显示如下:

    2、Header.vue

    (1)简介
      用于定义主页面的导航栏。
      通过导航栏,可以进行一些操作。比如:折叠侧边栏、修改密码、退出登录等。

    (2)定义页面内容

    <template>
        <div class="header">
            <!-- 是否展开侧边栏 -->
            <div class="header-title" @click="foldOrOpen">
                <a class="el-icon-s-fold" v-if="foldAside" title="折叠侧边栏" />
                <a class="el-icon-s-unfold" v-else title="展开侧边栏" />
            </div>
            <!-- 设置、文档、用户设置等 -->
            <div class="header-menu">
                <el-menu mode="horizontal" class="header-menu-submenu">
                    <!-- 设置 -->
                    <el-menu-item title="设置" index="1">
                        <i class="el-icon-setting"></i>设置
                    </el-menu-item>
                    <!-- 帮助文档 -->
                    <el-submenu title="帮助" index="2">
                        <template slot="title">
                            <i class="el-icon-info"></i>帮助
                        </template>
                        <el-menu-item index="2-1">
                            <a href="https://www.cnblogs.com/l-y-h/" target="_blank" class="header-submenu-a">博客地址</a>
                        </el-menu-item>
                        <el-menu-item index="2-2">
                            <a href="https://www.cnblogs.com/l-y-h/" target="_blank" class="header-submenu-a">代码地址</a>
                        </el-menu-item>
                    </el-submenu>
                    <!-- 用户设置 -->
                    <el-submenu title="用户设置" index="3">
                        <template slot="title">
                            <span class="header-span">
                                <img src="~@/assets/avatar.gif" :alt="userName"> {{ userName }}
                            </span>
                        </template>
                        <el-menu-item index="3-1" @click="showPasswordBox">
                            <i class="el-icon-edit"></i>修改密码
                        </el-menu-item>
                        <el-menu-item index="3-2" @click="logout">
                            <i class="el-icon-close"></i>退出
                        </el-menu-item>
                    </el-submenu>
                </el-menu>
            </div>
            <!-- 密码修改框 -->
            <UpdatePassword v-if="UpdatePasswordVisible" ref="updatePassowrd"></UpdatePassword>
        </div>
    </template>
    
    <script>
        import UpdatePassword from '@/views/home/UpdatePassword.vue'
        export default {
            name: 'Header',
            data() {
                return {
                    // 是否展开侧边栏
                    foldAside: true,
                    // 默认用户名
                    userName: 'admin',
                    // 是否展开密码框
                    UpdatePasswordVisible: false
                }
            },
            components: {
                // 引入密码框组件
                UpdatePassword
            },
            methods: {
                // 展开密码修改框
                showPasswordBox() {
                    this.UpdatePasswordVisible = true
                    // this.$nextTick 表示数据渲染后,执行密码框初始化
                    this.$nextTick(() => {
                        this.$refs.updatePassowrd.init()
                    })
                },
                // 展开、折叠侧边栏
                foldOrOpen() {
                    this.foldAside = !this.foldAside
                    // this.$emit 用于触发父组件的方法,并传递参数值
                    this.$emit("foldOrOpenAside", this.foldAside)
                },
                // 退出登录,回到登录界面
                logout() {
                    // TODO:退出逻辑待完成
                    alert("退出逻辑未完成");
                    this.$router.push({
                        name: "Login"
                    })
                }
            }
        }
    </script>
    
    <style>
        .header {
            padding: 0 10px;
            display: flex;
            height: 50px;
            line-height: 50px;
        }
    
        .header-title {
            height: 50px;
             50px;
            float: left;
            font-size: 50px;
            cursor: pointer;
        }
    
        .header-menu {
            height: 50px;
             100%;
            flex: 1;
            line-height: 50px;
            font-size: 30px;
        }
        .header-menu-submenu {
            float: right;
        }
        .header-submenu-a {
            text-decoration: none;
            color: #4CC4B8;
            font-weight: bold;
            font-size: 16px;
        }
        .header-submenu-a:hover {
            background-color: #2C3E50;
        }
        .el-menu--horizontal>.el-menu-item,
        .el-menu--horizontal>.el-submenu .el-submenu__title {
            height: 50px !important;
            line-height: 50px !important;
        }
        .el-menu--collapse .el-menu .el-submenu, .el-menu--popup {
            min- auto !important;
        }
        .header-span img {
             40px;
            height: 40px;
            line-height: 40px;
            margin: 5px 10px 10px 10px;
        }
        .header-span {
            font-size: 20px;
        }
    </style>

    (3)页面显示如下

    3、UpdatePassword.vue

    (1)简介
      定义密码修改框,用于修改用户密码。

    (2)定义页面内容

    <template>
        <el-dialog title="修改密码" :visible.sync="visible" :append-to-body="true">
            <el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" label-width="100px">
                <el-form-item label="账号">
                    <span>{{ userName }}</span>
                </el-form-item>
                <el-form-item label="原密码" prop="password">
                    <el-input type="password" v-model="dataForm.password" placeholder="原密码"></el-input>
                </el-form-item>
                <el-form-item label="新密码" prop="newPassword">
                    <el-input type="password" v-model="dataForm.newPassword" placeholder="新密码"></el-input>
                </el-form-item>
                <el-form-item label="确认密码" prop="confirmPassword">
                    <el-input type="password" v-model="dataForm.confirmPassword" placeholder="确认密码"></el-input>
                </el-form-item>
            </el-form>
            <span slot="footer" class="dialog-footer">
                <el-button @click="visible = false">取消</el-button>
                <el-button type="primary" @click="dataFormSubmit()">确定</el-button>
            </span>
        </el-dialog>
    </template>
    
    <script>
        export default {
            data() {
                return {
                    userName: 'admin',
                    visible: false,
                    dataForm: {
                        password: '',
                        newPassword: '',
                        confirmPassword: ''
                    },
                    dataRule: {
                        password: [{
                            required: true,
                            message: '原密码不能为空',
                            trigger: 'blur'
                        }],
                        newPassword: [{
                            required: true,
                            message: '新密码不能为空',
                            trigger: 'blur'
                        }],
                        confirmPassword: [{
                            required: true,
                            message: '确认密码不能为空',
                            trigger: 'blur'
                        }]
                    }
                }
            },
            methods: {
                // 初始化
                init() {
                    this.visible = true
                    // 初始化清空表单内容
                    this.$nextTick(() => {
                        this.$refs['dataForm'].resetFields()
                    })
                },
                // 表单提交,回到登录界面
                dataFormSubmit() {
                    // TODO: 表达提交逻辑待完成
                    alert("表达提交逻辑未完成")
                    this.visible = false;
                    this.$nextTick(() => {
                        this.$router.push({
                            name: "Login"
                        })
                    })
                }
            }
        }
    </script>

    (3)页面显示如下

    4、this.$nextTick 与 this.$emit 简单介绍

    (1)this.$nextTick
      其用于数据渲染之后执行。
    比如:
      修改了某个数据,这个数据需要 dom 更新之后才会显示出来,此时就可以使用 this.$nextTick。其传递一个回调函数,在数据渲染之后执行。

      在 Header.vue 中,就使用到了这个。如下所示:
        密码修改框通过 UpdatePasswordVisible 来控制是否显示。
        showPasswordBox() 方法被执行时,UpdatePassword 组件开始加载,数据渲染完成后触发 this.$nextTick 的回调函数,进行密码框的初始化。

    <!-- 密码修改框 -->
    <UpdatePassword v-if="UpdatePasswordVisible" ref="updatePassowrd"></UpdatePassword>
    
    
    // 展开密码修改框
    showPasswordBox() {
        this.UpdatePasswordVisible = true
        // this.$nextTick 表示数据渲染后,执行密码框初始化
        this.$nextTick(() => {
            this.$refs.updatePassowrd.init()
        })
    },

      若立即使用 this.$refs.updatePassowrd.init() 调用 UpdatePassword 的 init 方法,会报错,因为此时的 UpdatePassword  数据还未渲染,若想成功执行,需要使用 this.$nextTick,表示在数据渲染成功后执行。

    // 展开密码修改框
    showPasswordBox() {
        this.UpdatePasswordVisible = true
        this.$refs.updatePassowrd.init()
    },

    (2)this.$emit
      用于子组件向父组件传递数据,并触发父组件的方法。
      在Home.vue 与 Header.vue 中,就使用到了这个。如下所示:
        在 Home 组件里引入了 Header 组件,并定义了 @foldOrOpenAside 方法,
        在 Header 组件里通过 this.$emit 调用 foldOrOpenAside 方法,并传递数据(可选)。

    【Home.vue】
    <Header @foldOrOpenAside="foldOrOpen" />
    
    foldOrOpen(data) {
        this.foldAside = data
    }
    
    【Header.vue】
    <div class="header-title" @click="foldOrOpen"></div>
    // 展开、折叠侧边栏
    foldOrOpen() {
        this.foldAside = !this.foldAside
        // this.$emit 用于触发父组件的方法,并传递参数值
        this.$emit("foldOrOpenAside", this.foldAside)
    },

    5、Aside.vue

    (1)简介
      用于定义侧边栏,显示菜单。

    (2)定义页面内容

    <template>
        <div>
            <!-- 系统 Logo -->
            <el-aside class="header-logo" :width="asideWidth">
                <div @click="$router.push({ name: 'Home' })">
                    <a v-if="foldAside">后台管理中心</a>
                    <a v-else>后台</a>
                </div>
            </el-aside>
            <el-aside class="aside" :width="asideWidth" :class='"icon-size-" + iconSize'>
                <el-scrollbar style="height: 100%;  100%;">
                    <!--
                            default-active 表示当前选中的菜单,默认为 home。
                            collapse 表示是否折叠菜单,仅 mode 为 vertical(默认)可用。 
                            collapseTransition 表示是否开启折叠动画,默认为 true。
                            background-color 表示背景颜色。
                            text-color 表示字体颜色。
                        -->
                    <el-menu :default-active="menuActiveName || 'home'" :collapse="!foldAside" :collapseTransition="false"
                     background-color="#263238" text-color="#8a979e">
                        <el-menu-item index="home" @click="$router.push({ name: 'Home' })">
                            <i class="el-icon-s-home"></i>
                            <span slot="title">首页</span>
                        </el-menu-item>
                        <el-submenu index="demo">
                            <template slot="title">
                                <i class="el-icon-star-off"></i>
                                <span>demo</span>
                            </template>
                            <el-menu-item index="demo-echarts" @click="$router.push({ name: 'Echarts' })">
                                <i class="el-icon-s-data"></i>
                                <span slot="title">echarts</span>
                            </el-menu-item>
                            <el-menu-item index="demo-ueditor" @click="$router.push({ name: 'Ueditor' })">
                                <i class="el-icon-document"></i>
                                <span slot="title">ueditor</span>
                            </el-menu-item>
                        </el-submenu>
                    </el-menu>
                </el-scrollbar>
            </el-aside>
        </div>
    </template>
    
    <script>
        export default {
            name: 'Aside',
            props: ['foldAside'],
            data() {
                return {
                    // 保存当前选中的菜单
                    menuActiveName: 'home',
                    // 保存当前侧边栏的宽度
                    asideWidth: '200px',
                    // 用于拼接当前图标的 class 样式
                    iconSize: 'true'
                }
            },
            watch: {
                // 监视是否折叠侧边栏,折叠则宽度为 64px。
                foldAside(val) {
                    this.asideWidth = val ? '200px' : '64px'
                    this.iconSize = val
                }
            }
        }
    </script>
    
    <style>
        .aside {
            margin-bottom: 0;
            height: 100%;
            max-height: calc(100% - 50px);
             100%;
            max- 200px;
            background-color: #263238;
            text-align: left;
            right: 0;
        }
    
        .header-logo {
            background-color: #17b3a3;
            text-align: center;
            height: 50px;
            line-height: 50px;
             200px;
            font-size: 24px;
            color: #fff;
            font-weight: bold;
            margin-bottom: 0;
            cursor: pointer;
        }
        .el-submenu .el-menu-item {
            max- 200px !important;
        }
        .el-scrollbar__wrap {
            overflow-x: hidden !important;
        }
        .icon-size-false i {
            font-size: 30px !important;
        }
        .icon-size-true i {
            font-size: 18px !important;
        }
    </style>

    (3)页面显示如下

    6、props 简单介绍

      其用于父组件向子组件传递数据。
      在 Home.vue 和 Aside.vue 中,就使用到了这个。如下所示:
        在 Home.vue 中引入 Aside.vue 组件,并定义了 :foldAside 属性。
        在 Aside.vue 组件中,使用 props 可以获取到 这个 属性。

    【Home.vue】
    <!-- 侧边栏 -->
    <Aside :foldAside="foldAside" />
    
    【Aside.vue】
    props: ['foldAside'],

    7、Content.vue

    (1)简介
      用于定义各个菜单点击后的页面显示。

      同样需要使用 router 进行页面跳转(嵌套路由,通过 children 中的规则定义跳转路径),基本路由规则本文最后有介绍。

    (2)定义页面内容

    <template>
        <el-main class="content">
            <el-card class="card" shadow="hover">
                <keep-alive>
                    <router-view />
                </keep-alive>
            </el-card>
        </el-main>
    </template>
    
    <script>
        export default {
            name: 'Content'
        }
    </script>
    
    <style>
        .content {
            background-color: #f1f4f5;
        }
        .card {
            height: 100%;
        }
    </style>

    (3)页面显示如下

    8、定义 content 显示页面(仅供测试)

    【Ueditor.vue】
    <template>
        <div>
            <h1>Ueditor</h1>
        </div>
    </template>
    
    <script>
    </script>
    
    <style>
    </style>
    
    【HomePage.vue】
    <template>
        <div style="height: 800px;">
            <h1>HomePage</h1>
        </div>
    </template>
    
    <script>
    </script>
    
    <style>
    </style>
    
    【Echarts.vue】
    <template>
        <div>
            <h1>Echarts</h1>
        </div>
    </template>
    
    <script>
    </script>
    
    <style>
    </style>

    点击 Aside 中各个菜单,在 Content 会显示不同的 页面。

     

    9、基本路由问题

    (1)简介
      想要各个组件页面间能够顺利跳转,就需要 router 来操作了。
      此处简单写了路由跳转规则,后续会进行修改。

    (2)定义路由跳转规则
      path 指的是 路径。
      redirect 指的是 需要跳转的路径。
      name 指的是 路由的名字(此项目中,均使用 name 进行路由跳转)。
      component 指的是 路由的组件,用于显示页面(<router-view /> 会加载组件)。
      children 指的是 子路由(路由中显示另一个路由)。

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    import Home from '../views/Home.vue'
    
    Vue.use(VueRouter)
    
    const routes = [{
            path: '/',
            redirect: {
                name: "Login"
            }
        },
        {
            path: '/404',
            name: '404',
            component: () => import('@/components/common/404.vue')
        },
        {
            path: '/Login',
            name: 'Login',
            component: () => import('@/components/common/Login.vue')
        },
        {
            path: '/Home',
            name: 'Home',
            component: () => import('@/views/Home.vue'),
            redirect: {
                name: 'HomePage'
            },
            children: [{
                    path: '/Home/Page',
                    name: 'HomePage',
                    component: () => import('@/views/menu/HomePage.vue')
                },
                {
                    path: '/Home/Demo/Echarts',
                    name: 'Echarts',
                    component: () => import('@/views/menu/Echarts.vue')
                },
                {
                    path: '/Home/Demo/Ueditor',
                    name: 'Ueditor',
                    component: () => import('@/views/menu/Ueditor.vue')
                }
            ]
        },
    ]
    
    const router = new VueRouter({
        // routes 用于定义 路由跳转 规则
        routes,
        // mode 用于去除地址中的 #
        mode: 'history',
        // scrollBehavior 用于定义路由切换时,页面滚动。
        scrollBehavior: () => ({
            y: 0
        })
    })
    
    // 解决相同路径跳转报错
    const routerPush = VueRouter.prototype.push;
    VueRouter.prototype.push = function push(location, onResolve, onReject) {
        if (onResolve || onReject)
            return routerPush.call(this, location, onResolve, onReject)
        return routerPush.call(this, location).catch(error => error)
    };
    
    export default router
  • 相关阅读:
    阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_02 递归_2_练习_使用递归计算1-n之间的和
    阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_02 递归_1_递归概念&分类&注意事项
    阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_01 File类_8_File类遍历(文件夹)目录功能
    阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_01 File类_7_File类创建删除功能的方法
    阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_01 File类_6_File类判断功能的方法
    阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_01 File类_5_File类获取功能的方法
    阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_01 File类_4_File类的构造方法
    冒泡排序
    身份证验证合法性js--已验证
    演示工厂模式
  • 原文地址:https://www.cnblogs.com/l-y-h/p/12935300.html
Copyright © 2011-2022 走看看