Vue--》Vue3打造可扩展的项目管理系统后台的完整指南(三)

news2024/12/23 6:34:27

今天开始使用 vue3 + ts 搭建一个项目管理的后台,因为文章会将项目的每一个地方代码的书写都会讲解到,所以本项目会分成好几篇文章进行讲解,我会在最后一篇文章中会将项目代码开源到我的GithHub上,大家可以自行去进行下载运行,希望本文章对有帮助的朋友们能多多关注本专栏,学习更多前端vue知识,然后开篇先简单介绍一下本项目用到的技术栈都有哪几个方面(阅读本文章能够学习到的技术):

vite:快速轻量且功能丰富的前端构建工具,帮助开发人员更高效构建现代Web应用程序。

pnpm:高性能、轻量级npm替代品,帮助开发人员更加高效地处理应用程序的依赖关系。

Vue3:Vue.js最新版本的用于构建用户界面的渐进式JavaScript框架。

TypeScript:JavaScript的超集,提供了静态类型检查,使得代码更加健壮。

Animate:基于JavaScript的动画框架,它使开发者可以轻松创建各种炫酷的动画效果。

vue-router:Vue.js官方提供的路由管理器与Vue.js紧密耦合,非常方便与Vue.js一同使用。

Pinia:Vue3构建的Vuex替代品,具有响应式能力,提供非常简单的 API,进行状态管理。

element-plus:基于Vue.js 3.0的UI组件库,用于构建高品质的响应式Web应用程序。

axios:基于Promise的HTTP客户端,可以在浏览器和node.js中使用。

three:基于JavaScript的WebGL库,开发者可以编写高性能、高质量的3D场景呈现效果。

echarts:基于JavaScript的可视化图表库,支持多种类型的图表,可根据需要自行安装。

当然还有许多其他的需要安装的第三方库,这里就不再一一介绍了,在项目中用到的地方自行会进行讲解,大家自行学习即可,现在就让我们走进vue3+ts的实战项目吧。

目录

后台页面布局

左侧菜单栏布局

自定义导航菜单

顶部tabbar静态页面的搭建

菜单折叠效果


后台页面布局

今天我们采用 “经典三栏布局” ,它是一种常见的网页布局方式,通常在后台管理系统、企业门户网站等需要大量展示信息的网站中使用。左侧菜单栏用于导航界面,右侧上部可以用来展示头部信息和搜索框,而正文内容通常放在右侧中部,底部则放置一些网站相关的信息和链接。

三列式布局的优点是布局清晰,易于维护和扩展,同时也能够适应不同屏幕分辨率和设备类型的需求。在移动设备上,可以通过响应式设计等技术手段将其转化为单列布局或者其他适应屏幕的布局方式。今天就以手写方式进行该布局的实现:

首先我们先定义好三栏布局的html结构:

<template>
  <div class="layout">
    <!-- 左侧菜单 -->
    <div class="layout_slider">12</div>
    <div class="layout_tabbar">213</div>
    <div class="layout_main"></div>
    <div class="layout_fonter"></div>
  </div>
</template>

因为三栏布局项目中可能会有一些地方都用到到,这里我将一些三栏布局的变量封装成全局变量,当然我们这个项目是没有这种场景的,但是大项目中这样做可能会有一些奇效,这里提前做好:

在 第一篇文章 :已经讲解了如何封装全局CSS样式,忘记了的朋友可以回头翻翻看看,这里我在我定义好的全局scss样式表variable.scss文件中定义如下全局变量:

// 项目提供scss全局变量

// 左侧的菜单宽度
$base-menu-width: 260px;
// 左侧菜单的背景颜色
$base-menu-background: #4682B4;
// 顶部导航的高度
$base-tabbar-height: 60px;

接下来就是引用这些定义好的变量,然后通过计算宽度高度值来得到准确的布局样式,如下:

<style lang="scss" scoped>
.layout {
  width: 100%;
  height: 100vh;
  background: red;
  .layout_slider {
    width: $base-menu-width;
    height: 100vh;
    background: $base-menu-background;
  }
  .layout_tabbar {
    position: fixed;
    width: calc(100% - $base-menu-width);
    height: $base-tabbar-height;
    background: cyan;
    top: 0px;
    left: $base-menu-width;
  }
  .layout_main {
    position: absolute;
    width: calc(100% - $base-menu-width);
    height: calc(100vh - $base-tabbar-height * 2);
    background: #0f0;
    left: $base-menu-width;
    top: $base-tabbar-height;
    box-sizing: border-box;
    padding: 20px;
    overflow: auto;
  }
  .layout_fonter {
    position: fixed;
    width: calc(100% - $base-menu-width);
    height: $base-tabbar-height;
    background: cyan;
    bottom: 0;
    left: $base-menu-width;
  }
}
</style>

当然我们也可以在全局样式 index.scss 文件中定义我们想要的滚动条的效果(按照自己喜欢配置):

// 设置滚动条的样式
::-webkit-scrollbar{
  width: 5px;
}
::-webkit-scrollbar-track {
  background: white;
}
::-webkit-scrollbar-thumb {
  width: 8px;
  background-color: rgb(16, 20, 16);
  border-radius: 10px;
}

为了方便查看效果,我们给layout_main主体中添加一些高度让效果更加明显一点:

左侧菜单栏布局

左侧菜单栏是一种常见的前端界面元素,通常被用作网站或应用的导航和功能入口。它通常出现在页面的左侧,展示了一系列链接或按钮,用户可以通过点击这些链接或按钮实现页面间的切换或功能的开启。接下来将实现左侧菜单栏样式功能的书写:

logo样式设置:左侧菜单栏logo的话,这里我单独抽离出一个组件进行设置,在抽离出组件的同时这里我将存放logo图片和文字资源进行放置在一个单独的ts文件中,方便用户的修改:

import img from '../assets/images/logo1.jpg'
// 用于项目logo|标题配置
export default {
  title: '商品运营管理平台',
  logo: img,
  logoHidden: true, // logo组件是否隐藏设置
}

然后将该文件在logo组件中进行引入,然后配置一下相关样式,具体代码如下:

<template>
  <div class="logo" v-if="settings.logoHidden">
    <img :src="settings.logo" alt="logo图片" />
    <p>{{ settings.title }}</p>
  </div>
</template>

<script setup lang="ts">
// 引入设置logo与标题的配置文件
import settings from '@/utils/settings'
</script>

<style lang="scss" scoped>
.logo {
  width: 100%;
  height: $base-menu-logo-height;
  color: white;
  display: flex;
  align-items: center;
  box-sizing: border-box;
  padding: 10px;
  img {
    width: 40px;
    height: 40px;
  }
  p {
    font-size: $base-logo-title-fontSize;
    margin-left: 10px;
  }
}
</style>

菜单栏样式设置: 左侧菜单栏选项,这里的话我采用element-plus给我们提供的一些组件进行使用

首先我们先对左侧菜单栏的内容布局样式进行设置,这里采用element的滚动条样式进行设置:

计算滚动条的高度:

自定义导航菜单

这里通过自定义导航菜单的方式,不管导航菜单有多少,根据自己路由表配置的数量的多少而显示,相关步骤如下:

在Pinia仓库中进行存储生成菜单需要的数组(路由)

这里当导航菜单抽离出一个组件:

在导航组件中书写如下样式:

<template>
  <template v-for="item in menuList" :key="item.path">
    <!-- 没有子路由 -->
    <template v-if="!item.children">
      <el-menu-item
        v-if="!item.meta.hidden"
        :index="item.path"
        @click="goRoute"
      >
        <template #title>
          <el-icon>
            <component :is="item.meta.icon"></component>
          </el-icon>
          <span>{{ item.meta.title }}</span>
        </template>
      </el-menu-item>
    </template>
    <!-- 只有一个子路由 -->
    <template v-if="item.children && item.children.length == 1">
      <el-menu-item
        v-if="!item.children[0].meta.hidden"
        :index="item.children[0].path"
        @click="goRoute"
      >
        <template #title>
          <el-icon>
            <component :is="item.children[0].meta.icon"></component>
          </el-icon>
          <span>{{ item.children[0].meta.title }}</span>
        </template>
      </el-menu-item>
    </template>
    <!-- 有超过1个的子路由 -->
    <el-sub-menu
      :index="item.path"
      v-if="item.children && item.children.length > 1"
    >
      <template #title>
        <el-icon>
          <component :is="item.meta.icon"></component>
        </el-icon>
        <span>{{ item.meta.title }}</span>
      </template>
      <Menu :menuList="item.children"></Menu>
    </el-sub-menu>
  </template>
</template>

<script setup lang="ts">
import { useRouter } from 'vue-router'
// 获取父组件传递过来的全部路由数组
defineProps(['menuList'])
// 获取路由器对象
let $router = useRouter()
// 点击菜单的回调
const goRoute = (vc: any) => {
  $router.push(vc.index)
}
</script>
<script lang="ts">
export default {
  // eslint-disable-next-line vue/no-reserved-component-names
  name: 'Menu',
}
</script>
<style lang="scss" scoped></style>

然后我们在将路由出口位置也封装成一个组件:

在路由出口文件编写过渡动画增添点页面效果:

<template>
  <!-- 路由组件出口位置 -->
  <router-view v-slot="{ Component }">
    <transition name="fade">
      <!-- 渲染home主页下的一级路由组件下的子路由 -->
      <component :is="Component"></component>
    </transition>
  </router-view>
</template>
<script setup lang="ts"></script>
<style lang="scss" scoped>
.fade-enter-from {
  opacity: 0;
  transform: scale(0);
}
.fade-enter-active {
  transition: all 0.3s;
}
.fade-enter-leave {
  opacity: 1;
  transform: scale(1);
}
</style>

具体的结果如下:

这里有一个问题就是,当你点击某个菜单之后刷新页面,默认情况下所有的折叠菜单都会关闭的,如果你想在点击折叠菜单中的子菜单之后刷新页面当前选择的折叠菜单不进行折叠,可以通过如下方式实现:

顶部tabbar静态页面的搭建

在后台管理页面中,顶部 TabBar 组件的作用通常是帮助管理员快速切换不同的功能模块,方便管理各种信息和数据。后台管理页面通常包含了大量的功能模块和数据展示页面,例如用户管理、文章管理、订单管理等,这些页面之间可能存在复杂的关联和交互,因此需要一个能够方便、快速地进行页面切换的工具。

顶部tabbar组件我抽离出两部分,分别放置在顶部的两侧,如下:

<template>
  <div class="tabbar">
    <div class="tabbar_left">
      <Breadcrumb></Breadcrumb>
    </div>
    <div class="tabbar_right">
      <Setting></Setting>
    </div>
  </div>
</template>

<script setup lang="ts">
import Breadcrumb from './breadcrumb/index.vue'
import Setting from './seting/index.vue'
</script>

采用flex布局进行设置让其分布在顶部的两端:

<style lang="scss" scoped>
.tabbar {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: space-between;
  background-image: linear-gradient(
    to right,
    rgb(210, 179, 179),
    rgb(218, 202, 202),
    rgb(227, 206, 206)
  );
  align-items: center;
  .tabbar_left {
    display: flex;
    margin-left: 20px;
  }
  .tabbar_right {
    display: flex;
    align-items: center;
  }
}
</style>

在顶部的左侧我设置一个面包屑样式:

<template>
  <!-- 左侧的静态 -->
  <el-icon style="margin-right: 10px">
    <Expand></Expand>
  </el-icon>
  <!-- 左侧面包屑 -->
  <el-breadcrumb separator-icon="ArrowRight">
    <el-breadcrumb-item>权限管理</el-breadcrumb-item>
    <el-breadcrumb-item>用户管理</el-breadcrumb-item>
  </el-breadcrumb>
</template>

<script setup lang="ts"></script>

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

在顶部的右侧我设置element的按钮和下拉菜单:

<template>
  <el-button type="primary" size="small" icon="Refresh" circle></el-button>
  <el-button type="primary" size="small" icon="FullScreen" circle></el-button>
  <el-button type="primary" size="small" icon="Setting" circle></el-button>
  <img
    src="@/assets/images/bg4.jpg"
    style="width: 24px; height: 24px; border-radius: 50%; margin: 0 10px"
  />
  <!-- 下拉菜单 -->
  <el-dropdown>
    <span class="el-dropdown-link">
      admin
      <el-icon class="el-icon--right">
        <arrow-down />
      </el-icon>
    </span>
    <template #dropdown>
      <el-dropdown-menu>
        <el-dropdown-item>退出登录</el-dropdown-item>
      </el-dropdown-menu>
    </template>
  </el-dropdown>
</template>

<script setup lang="ts"></script>

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

最后的结果如下:

菜单折叠效果

在element-plus中已经给出了折叠面板的案例,接下来我将手写实现其案例:

在pinia仓库中定义一个布尔函数用于判断折叠面板的折叠与展开:

// 关于导航组件相关的仓库
import { defineStore } from 'pinia'

const useLayOutSettingStore = defineStore('SettingStore', {
  state: () => {
    return {
      fold: false, // 用户控制菜单折叠还是收起的控制
    }
  },
})

export default useLayOutSettingStore

给折叠面板的按钮添加点击事件来动态的切换面板样式:

<template>
  <!-- 左侧的静态 -->
  <el-icon style="margin-right: 10px" @click="changeIcon">
    <component :is="LayOutSettingStore.fold ? 'Fold' : 'Expand'"></component>
  </el-icon>
  <!-- 左侧面包屑 -->
  <el-breadcrumb separator-icon="ArrowRight">
    <el-breadcrumb-item>权限管理</el-breadcrumb-item>
    <el-breadcrumb-item>用户管理</el-breadcrumb-item>
  </el-breadcrumb>
</template>

<script setup lang="ts">
import useLayOutSettingStore from '@/store/settings'
// 获取仓库中layout相关配置的信息
let LayOutSettingStore = useLayOutSettingStore()

const changeIcon = () => {
  LayOutSettingStore.fold = !LayOutSettingStore.fold
}
</script>

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

改变状态值和面板样式之后,接下来给Menu设置可以折叠的属性:

本项目的导航页面功能的搭建就讲解到这,下一篇文章将讲解顶部tabber功能搭建和main主体内容,关注博主学习更多前端vue知识,您的支持就是博主创作的最大动力! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/593699.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Pytorch入门(二)神经网络的搭建

torch.nn中的nn全称为neural network,意思是神经网络&#xff0c;是torch中构建神经网络的模块。 文章目录 一、神经网络基本骨架二、认识卷积操作三、认识最大池化操作四、非线性激活五、线性层及其它层介绍六、简单的神经网络搭建七、简单的认识神经网络中的数值计算八、损失…

mmdetection训练coco数据集(继跑通后的一些工具使用)

&#xff08;仅做个人过程记录的笔记&#xff09; 1、生成中间件 可以选择评估方式 --eval &#xff0c;对于 COCO 数据集&#xff0c;可选 bbox 、segm、proposal 。可以得到result.bbox.json文件 生成pkl文件&#xff1a;faster_rcnn.pkl python tools/test.py config.py …

利用栈和队列共同解决迷宫问题

文章目录 什么是迷宫问题&#xff1f;如何解决迷宫问题&#xff1f;DFS&#xff08;深度优先搜索&#xff09;BFS&#xff08;广度优先搜索&#xff09; 总结 什么是迷宫问题&#xff1f; 迷宫问题是一道经典的算法问题&#xff0c;旨在寻找一条从起点到终点的最短路径。通常迷…

games101作业6

作业要求 Render() in Renderer.cpp: 将你的光线生成过程粘贴到此处&#xff0c;并且按照新框 架更新相应调用的格式。Triangle::getIntersection in Triangle.hpp: 将你的光线-三角形相交函数 粘贴到此处&#xff0c;并且按照新框架更新相应相交信息的格式。 在本次编程练习中…

删除排序链表中的重复元素(java)

删除链表中的重复元素 leetcode 83 题 删除链表中的重复元素解题思路代码链表专题 leetcode 83 题 删除链表中的重复元素 leetcode 83 题 – 跳转链接 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。…

Python numpy - 数组与矩阵的创建&运算

数组array 一 数组的创建 &#xff08;至少两个数组&#xff09;创建随机整数数组 a 和 b import numpy as np a np.random.randint(10,size20).reshape(4,5) b np.random.randint(10,size20).reshape(4,5) 二 数组常用函数 数组常用函数 函数作用unique&#xff08;&…

Transformer part2

(179条消息) Transformer模型入门详解及代码实现_transformer模型代码-CSDN博客 transformer的encoder和decoder的差别 1. decoder包含两个 Multi-Head Attention 层。 decoder第一个 Multi-Head Attention 层采用了 Masked 操作。 为什么需要Mask处理 如何进行Mask处理 de…

【C#图解教程】第五章 类的基本概念

程序和类 类是一个能储存数据并执行代码的经过封装的数据结构&#xff0c;包含数据成员和函数成员&#xff0c;类内通常会包含逻辑上相关的数据和函数&#xff0c;所以类通常会代表真实世界或概念上的事物。 运行中的C#程序实质上是许多实例之间相互作用&#xff1a; 类的声…

ThingsBoard 前端项目内置部件开发

ThingsBoard 是目前 Github 上最流行的开源物联网平台&#xff08;12.8k Star&#xff09;&#xff0c;可以实现物联网项目的快速开发、管理和扩展&#xff0c;是中小微企业物联网平台的不二之选。 本文介绍如何在 ThingsBoard 前端项目中开发内置的菜单导航部件。 内置相关部…

clickhouse简介

文章目录 1&#xff1a;简介1.1&#xff1a;CH是什么&#xff1f;1.2&#xff1a;CH优势1.3&#xff1a;架构设计 2&#xff1a;CH接口3&#xff1a;CH引擎1&#xff1a;数据库引擎3.1.1:mysql引擎 2&#xff1a;表引擎3.2.1&#xff1a;MergeTree3.2.2&#xff1a;集成引擎1&a…

电子合同签署协议开源版系统开发

电子合同签署协议开源版系统开发 H5TP6mysqlphp 源码开源不加密 以下是电子合同系统可能包含的功能列表&#xff1a; 用户注册和登录&#xff1a;用户可以注册并登录系统&#xff0c;以便创建、签署和管理合同。合同创建&#xff1a;用户可以创建新合同&#xff0c;包括填写合…

Web的基本漏洞--SQL注入漏洞

目录 一、SQL注入介绍 1.SQL注入漏洞原理 2.SQL注入漏洞的类型 3.SQL注入漏洞识别 4.攻击方式 5.SQL盲注 时间盲注 布尔盲注 报错盲注 6.SQL注入漏洞的危害 7.SQL注入漏洞的防范措施 8.SQL注入漏洞的绕过 一、SQL注入介绍 1.SQL注入漏洞原理 Web程序输入的数据传…

使用git rebase合并多次commit

目录 rebase的作用简要概括为&#xff1a;命令&#xff1a;解决冲突&#xff1a;遗留问题&#xff1a; rebase的作用简要概括为&#xff1a; 可以对某一段线性提交历史进行编辑、删除、复制、粘贴&#xff1b;因此&#xff0c;合理使用rebase命令可以使我们的提交历史干净、简…

docker安装php

在安装 php 之前&#xff0c;我们可以先查看一下我们的镜像&#xff1a; docker images 我这里是已经存在 php 镜像了&#xff0c;版本就是 TAG 显示的 8.1.16 如果没有镜像&#xff0c;则执行下面的命令&#xff0c;拉取 php 镜像&#xff1a; docker pull php:latest 请注…

MAYLAND HOME官网上线 | LTD家居家装行业案例分享

​一、公司介绍 在MAYLAND HOME&#xff0c;我们为我们对质量和服务的承诺感到自豪。我们相信我们的成功与客户的满意度直接相关&#xff0c;这就是为什么我们努力超越您的期望&#xff0c;我们承担的每一个项目。无论您是想升级您的家庭还是企业&#xff0c;我们都会在这里帮助…

SpringBoot3 CORS跨域访问

目录 Credentials 问题一 问题二 解决方法一 CrossOrigin&#xff0c;最优的方法 解决方法二 通过Filter 设置HTTP 解决方法三 通过实现WebMvcConfigurer设置HTTP HTTP 协议&#xff0c;需要认真的学习每个细节。 allowCredentials(true) 和 allowed-origins: "*&qu…

MySQL--万文长字探究隔离性实现原理

1 隔离性简介 事务具有原子性&#xff08;Atomicity&#xff09;、一致性&#xff08;Consistency&#xff09;、隔离性&#xff08;Isolation&#xff09;、持久性&#xff08;Durability&#xff09;四个特性&#xff0c;简称 ACID&#xff0c;缺一不可。这篇文章旨在讲清楚…

吐血整理 二叉树(链表实现)的基本操作详解!

文章目录 节点设置二叉树的深度优先遍历前序遍历中序遍历后序遍历 二叉树的广度优先遍历层序遍历 节点的个数叶子节点的个数第K层节点的个数值为X的节点树的最大深度翻转二叉树判断两颗二叉树是否相同判断二叉树是否是完全二叉树判断二叉树是否是单值二叉树判断二叉树是否是平衡…

有哪些好用的pdf修改器?思路提供

PDF格式的文档在现代生活中扮演着越来越重要的角色。但是&#xff0c;要编辑或修改PDF文件是一件非常困难的事情&#xff0c;因为PDF文件的格式和内容通常被锁定。为了解决这个问题&#xff0c;出现了PDF修改器这种工具&#xff0c;它可以帮助用户轻松地编辑和修改PDF文件。本文…

RDK X3 Module发布,全新软硬件平台加速实现量产级产品落地

机器人开发是一段美妙的旅程。GEEKROS创始人杨状状是地平线社区的一名开发者&#xff0c;热衷于鼓捣各类机器人&#xff0c;2022年&#xff0c;状状第一时间就拿到了地平线旭日X3派&#xff08;简称旭日X3派&#xff09;&#xff0c;基于TogetheROS™.Bot机器人操作系统&#x…