开发一个后台管理系统的主框架页面(登录、主界面、子界面)

登录

1. 找到 src/router/index.js 路由文件,添加登录路由代码:
{
  path: '/login',
  component: (resolve) => require(['@/views/login.vue'], resolve)
}
2. 在 src/views 目录下新增 login.vue 文件,内容如下:
<template>
  <div class="login-bg">
    <div class="login-box">
      <h2 class="login-tit">My Vue2</h2>
      <el-form :model="formData" @keyup.enter.native="submit">
        <el-form-item prop="userName">
          <el-input v-model="formData.userName" clearable prefix-icon="el-icon-user" placeholder="请输入用户名" autofocus></el-input>
        </el-form-item>
        <el-form-item prop="password">
          <el-input v-model="formData.password" clearable prefix-icon="el-icon-unlock" placeholder="请输入密码" show-password></el-input>
        </el-form-item>
        <p>用户名密码随意填写即可!</p>
        <el-button class="btn-submit" type="primary" @click="submit" :loading="loading">登 录</el-button>
      </el-form>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      loading: false,
      // 表单相关
      formData: {
        userName: '',
        password: ''
      }
    }
  },
  mounted() {
  },
  methods: {
    /**
     * 登录
     */
    submit() {
      this.loading = true
      this.$store.commit('SET_USER', { userName: this.formData.userName })
      this.$router.replace('/home')
    }
  }
}
</script>
<style lang="less" scoped>
.login-bg {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  background: #f7f7f7;
}
.login-box {
  width: 400px;
  padding: 20px;
  background: #fff;
  border-radius: 8px;
  .login-tit {
    margin-bottom: 20px;
    text-align: center;
  }
  .btn-submit {
    width: 100%;
  }
}
</style>

以上代码实现了一个简单的登录页面,在表单中输入用户名和密码后,点击登录按钮可以进行登录操作,并跳转到系统主页。

3. 定义表单验证文件

src/assets/scripts目录下新增一个名为validate.js的文件,内容如下:

export default {
  // 非空 输入框
  RI: { required: true, message: '请输入' },
  // 非空 选择器
  RS: { required: true, message: '请选择' },
  // 不以空格开头或结尾
  space: { pattern: /^[^\s]+(\s+[^\s]+)*$/, message: '不以空格开头或结尾' }
}

以上代码是一个验证规则的定义文件,通过导出一个对象来提供几个常用的验证规则。
这样我们就能将整个应用的验证规则都写在这个文件进行统一管理,避免后期维护时在页面组件中进行修改。

4. 在登录中使用定义的验证规则

打开之前新建的login.vue文件,在script中添加引入验证文件代码:

import V from '@/assets/scripts/validate'

export default {
  data() {
    return {
      V
    }
  }
}

template模板中,将规则绑定到表单项中:

<el-form-item prop="userName" :rules="[V.RI, V.space]">
···
</el-form-item>
<el-form-item prop="password" :rules="[V.RI], V.space">
···
</el-form-item>

提交时调用验证:

submit() {
  this.$refs.formData.validate((valid) => {
    if (valid) {
      this.loading = true
      this.$store.commit('SET_USER', { userName: this.formData.userName })
      this.$router.replace('/home')
    }
  })
}

login.vue文件修改完成后的完整内容如下:

<template>
  <div class="login-bg">
    <div class="login-box">
      <h2 class="login-tit">My Vue2</h2>
      <el-form :model="formData" ref="formData" @keyup.enter.native="submit">
        <el-form-item prop="userName" :rules="[V.RI, V.space]">
          <el-input v-model="formData.userName" clearable prefix-icon="el-icon-user" placeholder="请输入用户名" autofocus></el-input>
        </el-form-item>
        <el-form-item prop="password" :rules="[V.RI, V.space]">
          <el-input v-model="formData.password" clearable prefix-icon="el-icon-unlock" placeholder="请输入密码" show-password></el-input>
        </el-form-item>
        <p>用户名密码随意填写即可!</p>
        <el-button class="btn-submit" type="primary" @click="submit" :loading="loading">登 录</el-button>
      </el-form>
    </div>
  </div>
</template>

<script>
import V from '@/assets/scripts/validate'

export default {
  data() {
    return {
      V,
      loading: false,
      // 表单相关
      formData: {
        userName: '',
        password: ''
      }
    }
  },
  mounted() {
  },
  methods: {
    /**
     * 登录
     */
    submit() {
      this.$refs.formData.validate((valid) => {
        if (valid) {
          this.loading = true
          this.$store.commit('SET_USER', { userName: this.formData.userName })
          this.$router.replace('/home')
        }
      })
    }
  }
}
</script>
<style lang="less" scoped>
.login-bg {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  background: #f7f7f7;
}
.login-box {
  width: 400px;
  padding: 20px;
  background: #fff;
  border-radius: 8px;
  .login-tit {
    margin-bottom: 20px;
    text-align: center;
  }
  .btn-submit {
    width: 100%;
  }
}
</style>

这样我们一个基础的登录就完成了,其中包括了:进入页面自动聚焦到用户名输入框、密码框内容可见切换、登录表单中输入框聚焦时回车键触发提交事件、表单验证和验证成功后将输入的用户名放入Vuex用户对象中并跳转到首页。


# 主子界面路由嵌套
1. 在src/components目录中新建一个目录layout并在目录中新建一个名为wrap.vue的文件,内容如下:
<template>
  <div class="wrapper">
    <keep-alive>
      <router-view v-if="$route.meta.keepAlive"></router-view>
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive"></router-view>
  </div>
</template>

<script>
export default {
  data() {
    return {
    }
  },
  mounted() {
  },
  methods: {
  }
}
</script>

<style lang="less" scoped>
</style>

<keep-alive> 是 Vue 中的一个内置组件,用于保留组件状态并缓存组件实例。它可以在组件切换时将组件保存在内存中,以便下次再使用时不需要重新渲染和初始化组件。

在 Vue Router 配置中,可以通过嵌套多个 <router-view> 来构建复杂的页面布局。每个 <router-view> 将根据不同的路由匹配来渲染相应的组件内容,其中最外层 <router-view> 对应着根路由,而嵌套的 <router-view> 对应着子路由。
这样我们就能通过了文件中的 <router-view> 匹配渲染子路由的组件内容,从而实现主子页面的嵌套效果。

2. 新建首页页面组件

src/views/目录中新增一个名为home的子目录,并在新目录下添加一个名为 index.vue 的文件,内容如下:

<template>
  <div class="center">
    <h2>欢迎使用!</h2>
  </div>
</template>
<style lang="less" scoped>
  .center {
    display: grid;
    place-items: center;
    height: 100%;
  }
</style>

3. 配置路由

src/router/目录中新增一个名为menus.js的子路由文件,内容如下:

export default [
  {
    path: '/home',
    component: (resolve) => require(['@/views/home/index.vue'], resolve),
    meta: {
      keepAlive: true
    }
  },
  {
    path: '/one/two',
    component: (resolve) => require(['@/views/home/index.vue'], resolve)
  }
  // 其他菜单页面路由
]

上述代码中 meta 对象中 keepAlive 属性用于设置 wrap.vue<keep-alive> 标签的缓存是否开启。

找到src/router/index.js文件,引入wrap.vuemenus.js:

import wrap from '@/components/layout/wrap.vue'
import menusRouter from './menus' // 菜单路由

将原来的/home路由配置代码改为由嵌套的结构,并将子页面路由嵌套进去,内容如下:

{
  path: '/',
  component: wrap,
  children: menusRouter
}

src/router/index.js 路由文件修改完成后的完整代码内容如下:

import Vue from 'vue'
import VueRouter from 'vue-router'
import wrap from '@/components/layout/wrap.vue'
import menusRouter from './menus' // 菜单路由

Vue.use(VueRouter)

const pages = [
  {
    path: '/',
    component: wrap,
    children: menusRouter
  },
  {
    path: '/login',
    component: (resolve) => require(['@/views/login.vue'], resolve)
  },
  {
    path: '/errorPage/404',
    component: (resolve) => require(['@/views/404.vue'], resolve)
  }
]

const router = new VueRouter({
  routes: [
    // 默认路由
    {
      path: '/',
      redirect: '/home'
    },
    // 页面路由
    ...pages,
    // 没有匹配的路由重定向到404页面
    {
      path: '*',
      redirect: '/errorPage/404'
    }
  ]
})

// 路由跳转前
router.beforeEach((to, from, next) => {
  // 可用于拦截导航并执行一些操作,例如验证用户身份、权限控制等。
  next()
})

// 路由跳转后
router.afterEach((to, from) => {
  window.scrollTo(0, 0) // 每次路由改变滚动条都回到顶部
})

export default router

这样一个基本的主子界面路由嵌套关系就完成了,之后我们只需要在wrap.vue中添加主界面的基本功能:菜单栏、头部导航栏、子界面显示区域。

主子界面的基本功能和样式布局

菜单栏

菜单部分我们当前应用做常规的左侧菜单栏。

1. 在layout目录中新建一个名为menu-tree.vue的无限菜单组件文件,内容如下:
<template>
  <div class="menu-tree">
    <template v-for="item in menuList">
      <el-submenu :key="item.path" :index="item.path" v-if="item.children && item.children.length > 0">
        <template slot="title">
          <i :class="item.icon"></i>
          <span slot="title">{{item.title}}</span>
        </template>
        <!-- 组件自调用 -->
        <MenuTree :menuList="item.children"></MenuTree>
      </el-submenu>
      <el-menu-item :key="item.path" :index="item.path" v-else>
        <i :class="item.icon"></i>
        <span slot="title">{{item.title}}</span>
      </el-menu-item>
    </template>
  </div>
</template>

<script>
export default {
  name: 'MenuTree', // name 必须写用于组件自调用
  props: {
    // 菜单列表
    menuList: {
      type: Array,
      default: () => []
    }
  }
}
</script>
2. 在layout目录中新建一个名为menu.vue的菜单组件文件,并在其中使用无限菜单组件,内容如下:
<template>
  <div class="menu-box" :class="{'menu-collapse': isCollapse}">
    <i class="collapse-icon" :class="isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'" @click="isCollapse = !isCollapse"></i>
    <div class="menu-logo">
      <img class="logo-img" src="@img/logo.png" alt="logo">
      <span class="logo-name">My Vue2</span>
    </div>
    <el-scrollbar>
      <el-menu
        :default-active="$route.path"
        :collapse="isCollapse"
        :collapse-transition="false"
        unique-opened
        router
        background-color="#202123"
        text-color="#fff"
        active-text-color="#409EFF"
      >
        <MenuTree :menuList="menuList" />
      </el-menu>
    </el-scrollbar>
  </div>
</template>

<script>
import MenuTree from './menu-tree.vue'

export default {
  components: { MenuTree }, // 组件
  data() {
    return {
      isCollapse: false,
      menuList: [
        {
          path: '/home',
          title: '首页',
          icon: 'el-icon-s-home'
        },
        {
          path: '/one',
          title: '一级页面',
          icon: 'el-icon-menu',
          children: [
            {
              path: '/one/two',
              title: '二级页面'
            }
          ]
        }
      ]
    }
  },
  methods: {
  }
}
</script>

<style lang="less" scoped>
.menu-box {
  position: relative;
  flex-shrink: 0;
  width: 300px;
  background: #202123;
  transition: width .3s;
  &.menu-collapse {
    width: 64px;
    .logo-name {
      display: none;
    }
    /deep/ .el-submenu__title span {
      display: none;
    }
  }
  .collapse-icon {
    position: absolute;
    right: -30px;
    top: 15px;
    font-size: 30px;
    color: #fff;
  }
  .menu-logo {
    display: flex;
    align-items: center;
    padding: 0 15px;
    height: 60px;
    color: #fff;
    font-size: 20px;
    white-space: nowrap;
    overflow: hidden;
    .logo-img {
      margin-right: 10px;
      height: 30px;
    }
  }
  .el-scrollbar {
    height: calc(100% - 60px);
    /deep/ .el-scrollbar__wrap {
      overflow-x: hidden;
    }
  }
  .el-menu {
    border: 0;
  }
}
</style>
3. 在wrap.vue中引用组件并使用:

引入菜单组件

import Menu from './menu.vue'

注册组件

components: { Menu }, // 组件

template中使用组件

<Menu/>

wrap.vue修改后的完整内容如下:

<template>
  <div class="wrapper">
    <Menu />
    <keep-alive>
      <router-view v-if="$route.meta.keepAlive"></router-view>
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive"></router-view>
  </div>
</template>

<script>
import Menu from './menu.vue'

export default {
  components: { Menu }, // 组件
  data() {
    return {
    }
  },
  mounted() {
  },
  methods: {
  }
}
</script>

<style lang="less" scoped>
</style>
头部导航栏
1. 在 layout 目录下新建一个名为 header.vue 的头部导航栏组件,内容如下:
<template>
  <div class="header-box">
  </div>
</template>

<script>
export default {
  data() {
  },
  methods: {
  }
}
</script>

<style lang="less" scoped>
</style>
2. 在wrap.vue中引用组件并使用:

引入菜单组件

import Header from './header.vue'

注册组件

components: { Header }, // 组件

template中使用组件,并修改菜单组件、头部组件、子界面容器的代码结构:

<template>
  <div class="wrapper">
    <Menu />
    <div class="header-subpage-content">
      <Header />
      <div class="subpage-content">
        <keep-alive>
          <router-view v-if="$route.meta.keepAlive"></router-view>
        </keep-alive>
        <router-view v-if="!$route.meta.keepAlive"></router-view>
      </div>
    </div>
  </div>
</template>

添加主子界面布局样式

.wrapper {
  display: flex;
  width: 100%;
  height: 100vh;
  .header-subpage-content {
    display: flex;
    flex-direction: column;
    width: 100%;
    .subpage-content {
      height: 100%;
    }
  }
}

wrap.vue修改后的完整内容如下:

<template>
  <div class="wrapper">
    <Menu />
    <div class="header-subpage-content">
      <Header />
      <div class="subpage-content">
        <keep-alive>
          <router-view v-if="$route.meta.keepAlive"></router-view>
        </keep-alive>
        <router-view v-if="!$route.meta.keepAlive"></router-view>
      </div>
    </div>
  </div>
</template>

<script>
import Menu from './menu.vue'
import Header from './header.vue'

export default {
  components: { Menu, Header }, // 组件
  data() {
    return {
    }
  },
  mounted() {
  },
  methods: {
  }
}
</script>

<style lang="less" scoped>
  .wrapper {
    display: flex;
    width: 100%;
    height: 100vh;
    .header-subpage-content {
      display: flex;
      flex-direction: column;
      width: 100%;
      .subpage-content {
        height: 100%;
      }
    }
  }
</style>
3. 用户基本操作模块(用户头像、用户名、退出登录)

header.vue 中内容替换为以下内容:

<template>
  <div class="header-box">
    <el-dropdown class="user-dropdown" @command="handleUser">
      <img class="user-pic" src="@img/pic.png" />
      <el-dropdown-menu slot="dropdown">
        <el-dropdown-item disabled>{{ $store.getters.GET_USER.userName }}</el-dropdown-item>
        <el-dropdown-item command="logout" divided>退出登录</el-dropdown-item>
      </el-dropdown-menu>
    </el-dropdown>
  </div>
</template>

<script>
export default {
  data() {
    return {
    }
  },
  methods: {
    /**
     * 用户相关操作
     * @param {String} functionName 函数名称
     */
    handleUser(functionName) {
      this[functionName]()
    },
    /**
     * 退出登录
     */
    logout() {
      this.$router.replace('/login')
    }
  }
}
</script>

<style lang="less" scoped>
  .header-box {
    min-height: 60px;
    color: #fff;
    background: #202123;
    .user-dropdown {
      float: right;
      display: flex;
      align-items: center;
      margin-right: 10px;
      height: 100%;
      color: #fff;
      cursor: pointer;
      .user-pic {
        width: 40px;
        height: 40px;
      }
    }
  }
</style>

到这里整个后台管理系统的基本主框架页面就完成了,后续再根据自己的添加或修改内容。



框架搭建整体流程

点击下载步骤 1-7 配置完成的完整 Demo



本框架更多功能 Demo 下载

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值