第十三篇 - 写一个侧边栏导航页面

发布时间 2023-07-13 11:53:17作者: o云淡风轻o

参考链接:https://github.com/newbee-ltd/vue3-admin

今天创建一个侧边栏导航页面,上一节并没有写NavigationTest.vue的功能,今天来丰富它。

今天想实现的侧边栏是

 

点击Home,右侧显示Home的内容,点击About,右侧显示About的内容。

首先我们看一下布局如何

 看这个布局,就可以发现,侧边栏是NavigationTest.vue,头部区域是HeaderTest.vue,底部区域是Footer.vue,中间主体区域是其他跳转页面,因为此次写Home和About,所以会有HomeTest.vue和AboutTest.vue,总计新增4个页面

 首先我们将这四个页面写完。

NavigationTest.vue

<template>
  <div class="layout">
    <el-container class="container">
      <el-aside class="aside">
        <div class="head">
          <div>
            <span>vue3 admin</span>
          </div>
        </div>
        <div class="line" />
        <el-menu
            background-color="#222832"
            text-color="#fff"
            :router="true"
            :default-openeds="state.defaultOpen"
            :default-active='state.currentPath'
        >
          <el-sub-menu index="1">
            <template #title>
              <span>目录1</span>
            </template>
          </el-sub-menu>
          <el-sub-menu index="2">
            <template #title>
              <span>目录2</span>
            </template>
            <el-menu-item-group>
              <el-menu-item index="/HomeTest">Home</el-menu-item>
              <el-menu-item index="/AboutTest">About</el-menu-item>
            </el-menu-item-group>
          </el-sub-menu>
        </el-menu>
      </el-aside>
      <el-container class="content">
        <HeaderTest />
        <div class="main">
          <router-view />
        </div>
        <FooterTest />
      </el-container>
    </el-container>
  </div>
</template>

<script setup>
import { reactive } from 'vue'
import { useRouter } from 'vue-router'
import HeaderTest from "@/views/HeaderTest.vue"
import FooterTest from "@/views/FooterTest.vue"

const noMenu = ['/LoginPage']
const router = useRouter()
const state = reactive({
  showMenu: true,
  defaultOpen: ['1', '2', '3', '4'],
  currentPath: '/',
})

router.afterEach((to) => {
  state.showMenu = !noMenu.includes(to.path)
})

router.beforeEach((to) => {
  state.currentPath = to.path
  document.title = to.name
})
</script>

<style scoped>
.layout {
  min-height: 100vh;
  background-color: #ffffff;
}
.container {
  height: 100vh;
}
.aside {
  width: 200px!important;
  background-color: #222832;
}
.head {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 50px;
}
.head > div {
  display: flex;
  align-items: center;
}

.head img {
  width: 50px;
  height: 50px;
  margin-right: 10px;
}
.head span {
  font-size: 20px;
  color: #ffffff;
}
.line {
  border-top: 1px solid hsla(0,0%,100%,.05);
  border-bottom: 1px solid rgba(0,0,0,.2);
}
.content {
  display: flex;
  flex-direction: column;
  max-height: 100vh;
  overflow: hidden;
}
.main {
  height: calc(100vh - 100px);
  overflow: auto;
  padding: 10px;
}
</style>

<style>
body {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}
.el-menu {
  border-right: none!important;
}
.el-submenu {
  border-top: 1px solid hsla(0, 0%, 100%, .05);
  border-bottom: 1px solid rgba(0, 0, 0, .2);
}
.el-submenu:first-child {
  border-top: none;
}
.el-submenu [class^="el-icon-"] {
  vertical-align: -1px!important;
}
a {
  color: #409eff;
  text-decoration: none;
}
.el-pagination {
  text-align: center;
  margin-top: 20px;
}
.el-popper__arrow {
  display: none;
}
</style>
View Code

 

HeaderTest.vue

<script setup>

</script>

<template>
  <h1>首页</h1>
</template>

<style scoped>

</style>
View Code

 

FooterTest.vue

<script>
export default {
  data () {
  }
}

</script>

<template>
  <div>copyright@</div>
</template>

<style scoped>

</style>
View Code

 

HomeTest.vue

<!--/src/views/home.vue-->
<template><h1>Home Page</h1>
  <p> {{ pageData }} </p></template>
<script>
export default {
  data () {
    return {
      // 数据绑定对象
      pageData: 'Welcome to home page'
      }
    }
}

</script>
View Code

 

AboutTest.vue

<!--/src/views/home.vue-->
<template><h1>About Page</h1>
  <p> {{ pageData }} </p></template>
<script>
export default {
  data () {
    return {
      // 数据绑定对象
      pageData: 'Welcome to About page'
    }
  }
}

</script>
View Code

 

接下来去更新路由routes.js

import LoginPage from '@/views/LoginPage.vue'
import JumpTest from '@/views/JumpTest.vue'
import HomeTest from '@/views/HomeTest.vue'
import AboutTest from "@/views/AboutTest.vue";

const routes = [
    {
        name: 'LoginPage',
        path: '/',
        component: LoginPage
    },
    {
        name: '/JumpTest',
        path: '/JumpTest',
        redirect: '/HomeTest',
        component: JumpTest,
        children: [
            {path: '/HomeTest', name: 'HomeTest', component: HomeTest},
            {path: '/AboutTest', name: 'AboutTest', component: AboutTest}
        ]
    }
];
export default routes
View Code

 

为了使代码完整,将其他几个文件也贴出来吧

LoginPage.vue

/* eslint-disable */
<template>
  <div class="login_container">
    <div class="login_box">
      <div class="wai">
        <!-- 头像区域 -->
        <div class="avatar_box">
          <img src="../assets/head.png" alt="" />
        </div>
        <!-- 登录表单区域 -->
        <el-form
            ref="loginFormRef"
            :model="loginForm"
            :rules="loginFormRules"
            label-width="0px"
            class="login_form"
        >
          <!--        用户名-->
          <el-form-item prop="username">
            <label class="form-label">用户名</label>
            <el-input
                v-model="loginForm.username"
                prefix-icon="User"
            ></el-input>
          </el-form-item>
          <!--        密码-->
          <el-form-item prop="password">
            <label class="form-label">密码</label>
            <el-input
                v-model="loginForm.password"
                prefix-icon="Key"
                type="password"
            ></el-input>
          </el-form-item>
          <!--        按钮区域-->
          <el-form-item class="btns">
            <el-button type="primary" @click="Login">登录</el-button>
            <el-button type="info" @click="resetLoginForm">重置</el-button>
          </el-form-item>
          <div style="display:flex; justify-content:flex-start">{{loginForm.message}}</div>
        </el-form>
      </div>
    </div>
  </div>
</template>

<style lang="less" scoped>
.login_container {
  background-color: darkcyan;
  height: 100%;
}

.login_box {
  width: 350px;
  height: 300px;
  background-color: white;
  border-radius: 15px;
  /*容器内居中*/
  position: absolute;
  left: 40%;
  top: 50%;
  transform: translate(-50%, -50%);

  .avatar_box {
    height: 130px;
    width: 130px;
    border: 1px solid #eee;
    border-radius: 50%;
    padding: 10px;
    /*边框阴影*/
    box-shadow: 0 0 10px #ddd;
    position: absolute;
    left: 50%;
    transform: translate(-50%, -50%);
    background-color: #fff;

    img {
      width: 100%;
      height: 100%;
      border-radius: 50%;
      background-color: #993d3d;
    }
  }

  .login_form {
    position: absolute;
    bottom: 0;
    width: 100%;
    padding: 0 20px;
    box-sizing: border-box;
  }

  .btns {
    display: flex;
    justify-content: flex-end;
  }
  .wai {
    background-image: url("../assets/back.jpg");
    width: 577px;
    height: 300px;
    border-radius: 15px;
  }
}
</style>

<script>
import qs from 'qs'

export default {
  name: 'LoginPage',
  data () {
    return {
      // 数据绑定对象
      loginForm: {
        username: 'lili',
        password: '123',
        message: ''
      },
      loginFormRules: {
        // 验证用户
        username: [
          {required: true, message: '请输入用户名', trigger: 'blur'},
          {
            min: 3,
            max: 10,
            message: '长度在3到10个字符',
            trigger: 'blur'
          }
        ],
        password: [
          {required: true, message: '请输入登录密码', trigger: 'blur'},
          {
            min: 3,
            max: 15,
            message: '长度在3到15个字符',
            trigger: 'blur'
          }
        ]
      }
    }
  },
  methods: {
    Login () {
      /* http://localhost:8081/api/login */
      this.$axios
          .post('http://localhost:8081/api/login', qs.stringify(this.loginForm))
          .then(successResponse => {
            console.log(successResponse.data)
            if (successResponse.data.code !== 200) {
              this.loginForm.message = successResponse.data.message
            } else {
              console.log('登录成功')
              this.$router.push({path: '/JumpTest'})
            }
          })
          .catch(failResponse => {
            console.log('12345566')
            console.log(failResponse)
          })
    },
    // // 重置登录表单
    resetLoginForm () {
      this.$refs.loginFormRef.resetFields()
    }
  }
}
</script>
View Code

 

JumpTest.vue

/* eslint-disable */
<template>
  <NavigationTest></NavigationTest>
</template>
<script>

import NavigationTest from "@/views/NavigationTest.vue";

export default {
  name: 'JumpTest',
  components: {
    NavigationTest
  }
}

</script>
<style scoped>

</style>
View Code

 

App.vue

<template>
  <router-view/>
</template>

<script>

export default {
  name: 'App',
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
View Code

 

main.js

import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
import './assets/css/global.css'
import axios from 'axios'
// 统一导入el-icon图标
import * as ElIconModules from '@element-plus/icons-vue'
import router  from "./router/index"

const app = createApp(App)

app.config.productionTip = false
app.config.globalProperties.$axios = axios

for (let iconName in ElIconModules) {
    app.component(iconName, ElIconModules[iconName])
}

app.use(router)
app.use(ElementPlus)
app.mount('#app')
View Code

 

运行程序试试npm run serve