vue后台管理系统从0到1(5)

文章目录

  • vue后台管理系统从0到1(5)
    • 完善侧边栏
    • 修改bug
    • 渲染header导航栏

vue后台管理系统从0到1(5)

在这里插入图片描述
接上一期,我们需要完善我们的侧边狼

完善侧边栏

我们在 element 组件中可以看见,这一个侧边栏是符合我们的要求的
在这里插入图片描述
我们就使用这样一个侧边栏动态渲染我们的各个选项,但是目前没有接入后端接口,我们需要自己先定义静态侧边栏数据,然后在使用v-for动态渲染上去

在这里插入图片描述
这是我写好的侧边栏动态v-for渲染代码
在这里插入图片描述

这里是渲染数据和渲染方法

在这里插入图片描述

这里是加上的样式

以上代码,不懂的自己查gpt或者查一些ai

CommonAside.vue 完整代码

<template>
  <el-aside width="200px">
    <el-menu @select="handleMenuSelect" background-color="#545c64" text-color="#fff">
      <h3>通用后台管理系统</h3>
      <el-menu-item
          v-for="item in noChildren"
          :index="item.path"
          :key="item.path"
      >
        <i :class="item.icon"></i>
        <span>{{ item.label }}</span>
      </el-menu-item>

      <el-sub-menu
          v-for="item in hasChildren"
          :index="item.path"
          :key="item.path"
      >
        <template #title>
          <i :class="item.icon"></i>
          <span>{{ item.label }}</span>
        </template>
        <el-menu-item
            v-for="subItem in item.children"
            :index="subItem.path"
            :key="subItem.path"
        >
          <i :class="subItem.icon"></i>
          <span>{{ subItem.label }}</span>
        </el-menu-item>
      </el-sub-menu>
    </el-menu>
  </el-aside>
</template>

<script setup>
import { ref, computed } from 'vue';
import { useRouter } from 'vue-router';

const router = useRouter();
const list = ref([
  { path: '/home', name: 'home', label: '首页', icon: 'el-icon-house', url: 'Home' },
  { path: '/mall', name: 'mall', label: '商品管理', icon: 'el-icon-video-play', url: 'Mall' },
  { path: '/user', name: 'user', label: '用户管理', icon: 'el-icon-user', url: 'User' },
  {
    path: '/other', label: '其他', icon: 'el-icon-location',
    children: [
      { path: '/page1', name: 'page1', label: '页面1', icon: 'el-icon-setting', url: 'Page1' },
      { path: '/page2', name: 'page2', label: '页2', icon: 'el-icon-setting', url: 'Page2' }
    ]
  }
]);

const noChildren = computed(() => list.value.filter(item => !item.children));
const hasChildren = computed(() => list.value.filter(item => item.children));

const handleMenuSelect = (index) => {
  const item = list.value.find(item => item.path === index) ||
      list.value.flat().find(item => item.path === index);
  if (item) {
    router.push(item.path);
  }
};
</script>

<style lang="less" scoped>
.icons {
  width: 18px;
  height: 18px;
  margin-right: 5px;
}

.el-menu{
  border-right: none;
  h3{
    line-height: 48px;
    color: #fff;
    text-align: center;
  }
}

.el-aside{
  height: 10000px;
  background-color: #545c64;
}

</style>

为了防止出错,重构 Main.vue 代码如下,不懂的gpt,我认为重要的是整个项目完成的流程
在这里插入图片描述

<script setup>
// 可以在这里添加组件的逻辑
import CommonAside from '@/components/CommonAside.vue'
</script>

<template>
  <div class="common-layout">
    <el-container>
      <el-aside width="200px"  class="aside-container">
        <!-- 侧边栏内容 -->
        <common-aside></common-aside>
      </el-aside>
      <el-container>
        <el-header class="el-header">
          <common-header></common-header>
        </el-header>
        <el-main class="right-main">
          main
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>

<style>

.common-layout{
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
}
el-container{
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
}
.el-header{
  background-color: #333;
}
</style>

然后就是重新跑项目:
在这里插入图片描述
如果对于以上代码有问题可以私信我,我们的侧边栏就渲染完成了,这里有一个bug,就是我们的 icon 没有加载出来,我还没有发现问题在哪,如果你们发现了,可以私信我。
紧接着上文,我们的项目目前仍然存在侧边栏 icon 加载问题,我今天好好的看了一下代码,发现展示 icon 的地方代码出了问题

修改bug

在这里插入图片描述
这是我修改过的代码

我原本写的展示 icon 使用 标签,并且把 icon 的渲染写成了 class 属性里

重构 commonAside.vue 如下:

<template>
  <el-aside width="200px">
    <el-menu @select="handleMenuSelect" background-color="#545c64" text-color="#fff">
      <h3>通用后台管理系统</h3>
      <el-menu-item
          v-for="item in noChildren"
          :index="item.path"
          :key="item.path"
      >
        <component class="icons" :is="item.icon"></component>
        <span>{{ item.label }}</span>
      </el-menu-item>

      <el-sub-menu
          v-for="item in hasChildren"
          :index="item.path"
          :key="item.path"
      >
        <template #title>
          <component class="icons" :is="item.icon"></component>
          <span>{{ item.label }}</span>
        </template>
        <el-menu-item
            v-for="subItem in item.children"
            :index="subItem.path"
            :key="subItem.path"
        >
          <component class="icons" :is="subItem.icon"></component>
          <span>{{ subItem.label }}</span>
        </el-menu-item>
      </el-sub-menu>
    </el-menu>
  </el-aside>
</template>

<script setup>
import { ref, computed } from 'vue';
import { useRouter } from 'vue-router';

const router = useRouter();
const list = ref([
  { path: '/home', name: 'home', label: '首页', icon: 'house', url: 'Home' },
  { path: '/mall', name: 'mall', label: '商品管理', icon: 'video-play', url: 'Mall' },
  { path: '/user', name: 'user', label: '用户管理', icon: 'user', url: 'User' },
  {
    path: '/other', label: '其他', icon: 'location',
    children: [
      { path: '/page1', name: 'page1', label: '页面1', icon: 'setting', url: 'Page1' },
      { path: '/page2', name: 'page2', label: '页2', icon: 'setting', url: 'Page2' }
    ]
  }
]);

const noChildren = computed(() => list.value.filter(item => !item.children));
const hasChildren = computed(() => list.value.filter(item => item.children));

const handleMenuSelect = (index) => {
  const item = list.value.find(item => item.path === index) ||
      list.value.flat().find(item => item.path === index);
  if (item) {
    router.push(item.path);
  }
};
</script>

<style lang="less" scoped>
.icons {
  width: 18px;
  height: 18px;
  margin-right: 5px;
}

.el-menu{
  border-right: none;
  h3{
    line-height: 48px;
    color: #fff;
    text-align: center;
  }
}

.el-aside{
  height: 10000px;
  background-color: #545c64;
}

</style>

渲染header导航栏

然后我们接着渲染我们的 header 导航栏部分,目标是渲染成这样
在这里插入图片描述
那么第一步分析界面布局

可以得出以下两个部分,也是我们需要分开写的两个部件

首先,使用一个 header 把整体包起来

  <div class="header">
    
    
  </div>

然后我们把导航栏分成左右两部分,左边有图标和首页字体,右边是用户头像

  <div class="header">
    <div class="l-content">
    
    </div>

    <div class="r-content">
      
    </div>
    
  </div>

然后我们具体实现左右两边的东西

  <div class="header">
    <div class="l-content">
    	//图标
      <el-button size="small">
        <component class="icons" is="menu"></component>
      </el-button>
		//面包屑字体
      <el-breadcrumb separator="/" class="bread">
        <el-breadcrumb-item :to="{path:'/'}">首页</el-breadcrumb-item>
      </el-breadcrumb>
      
    </div>

    <div class="r-content">
    //用户头像
     <el-dropdown>
    <span class="el-dropdown-link">
      <img :src="getImageUrl(user)" class="user"/>
    </span>
        <template #dropdown>
        //单击头像退出按钮
          <el-dropdown-menu>
            <el-dropdown-item>个人中心</el-dropdown-item>
            <el-dropdown-item>退出</el-dropdown-item>
          </el-dropdown-menu>
        </template>
      </el-dropdown>
      
    </div>
  </div>

然后我们加入样式

<style lang="less" scoped>
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  height: 100%;
  background-color: #333;

}

.icons {
  width: 20px;
  height: 20px;
}

.l-content {
    display: flex;
    align-items: center;
    .el-button{
      margin-right: 20px;
    }
  }


.r-content  {
  .user{
    width: 40px;
    height: 40px;
    border-radius: 50%;
  }
}

/* 注意::deep() 是一个 Vue.js 中的作用域穿透伪元素,用于在 scoped CSS 中访问子组件的样式。
   但它不是标准的 CSS 语法,且在新版本的 Vue.js 中可能已经被废弃或替换。
   如果这段代码是在 Vue.js 项目中使用的,请确保你的项目支持这种语法。
   此外,由于选择器中包含特殊字符(如点号和括号),你可能需要对其进行适当的转义或使用其他方法来实现相同的效果。
   但在这里,为了保持原始信息的完整性,我保留了这段代码的原样。 */
:deep(.bread span) {
  color: #fff !important;
  cursor: pointer !important;
}

</style>

再加入渲染数据的代码

<script setup>
import {ref, computed} from 'vue';
import {useRouter} from 'vue-router';

const router = useRouter();
const list = ref([
  {path: '/home', name: 'home', label: '首页', icon: 'el-icon-house', url: 'Home'},
  {path: '/mall', name: 'mall', label: '商品管理', icon: 'el-icon-video-play', url: 'Mall'},
  {path: '/user', name: 'user', label: '用户管理', icon: 'el-icon-user', url: 'User'},
  {
    path: '/other', label: '其他', icon: 'el-icon-location',
    children: [
      {path: '/page1', name: 'page1', label: '页面1', icon: 'el-icon-setting', url: 'Page1'},
      {path: '/page2', name: 'page2', label: '页2', icon: 'el-icon-setting', url: 'Page2'}
    ]
  }
]);

const getImageUrl = (user) => {
  return new URL(`../assets/images/${user}.png`, import.meta.url).href;
};
</script>

最后整合代码:
CommonHeader.vue代码:

<template>
  <div class="header">
    <div class="l-content">
      <el-button size="small">
        <component class="icons" is="menu"></component>
      </el-button>

      <el-breadcrumb separator="/" class="bread">
        <el-breadcrumb-item :to="{path:'/'}">首页</el-breadcrumb-item>
      </el-breadcrumb>
    </div>

    <div class="r-content">
      <el-dropdown>
    <span class="el-dropdown-link">
      <img :src="getImageUrl(user)" class="user"/>
    </span>
        <template #dropdown>
          <el-dropdown-menu>
            <el-dropdown-item>个人中心</el-dropdown-item>
            <el-dropdown-item>退出</el-dropdown-item>
          </el-dropdown-menu>
        </template>
      </el-dropdown>
    </div>
  </div>


</template>

<script setup>
import {ref, computed} from 'vue';
import {useRouter} from 'vue-router';

const router = useRouter();
const list = ref([
  {path: '/home', name: 'home', label: '首页', icon: 'el-icon-house', url: 'Home'},
  {path: '/mall', name: 'mall', label: '商品管理', icon: 'el-icon-video-play', url: 'Mall'},
  {path: '/user', name: 'user', label: '用户管理', icon: 'el-icon-user', url: 'User'},
  {
    path: '/other', label: '其他', icon: 'el-icon-location',
    children: [
      {path: '/page1', name: 'page1', label: '页面1', icon: 'el-icon-setting', url: 'Page1'},
      {path: '/page2', name: 'page2', label: '页2', icon: 'el-icon-setting', url: 'Page2'}
    ]
  }
]);

const getImageUrl = (user) => {
  return new URL(`../assets/images/${user}.png`, import.meta.url).href;
};
</script>

<style lang="less" scoped>
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  height: 100%;
  background-color: #333;

}

.icons {
  width: 20px;
  height: 20px;
}

.l-content {
    display: flex;
    align-items: center;
    .el-button{
      margin-right: 20px;
    }
  }


.r-content  {
  .user{
    width: 40px;
    height: 40px;
    border-radius: 50%;
  }
}

/* 注意::deep() 是一个 Vue.js 中的作用域穿透伪元素,用于在 scoped CSS 中访问子组件的样式。
   但它不是标准的 CSS 语法,且在新版本的 Vue.js 中可能已经被废弃或替换。
   如果这段代码是在 Vue.js 项目中使用的,请确保你的项目支持这种语法。
   此外,由于选择器中包含特殊字符(如点号和括号),你可能需要对其进行适当的转义或使用其他方法来实现相同的效果。
   但在这里,为了保持原始信息的完整性,我保留了这段代码的原样。 */
:deep(.bread span) {
  color: #fff !important;
  cursor: pointer !important;
}

</style>

然后,我们启动项目,查看如下:
在这里插入图片描述
这样一个新的组件就被我们写好了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【操作系统】06.进程控制

一、进程创建 1.1 认识fork函数 在linux中fork函数是非常重要的函数&#xff0c;它从已存在进程中创建一个新进程。新进程为子进程&#xff0c;而原进程为父进程。 进程调用fork&#xff0c;当控制转移到内核中的fork代码后&#xff0c;内核将 分配新的内存块和内核数据结构…

Aspose.PDF功能演示:使用 JavaScript 从 PDF 中提取文本

在数据提取、业务文档自动化和文本挖掘方面&#xff0c;使用 JavaScript 从PDF中提取文本非常有用。它允许开发人员自动执行从 PDF 收集信息的过程&#xff0c;从而显著提高处理大量文档的生产力和效率。在这篇博文中&#xff0c;我们将学习如何使用 JavaScript 从 PDF 中提取文…

人工智能的未来应用与发展前景

随着人工智能&#xff08;AI&#xff09;技术的快速进步&#xff0c;我们正亲历着它在各行各业中带来的巨大变革。无论是医疗、企业管理&#xff0c;还是日常生活&#xff0c;AI 技术都在改变着我们的工作和生活方式。那么&#xff0c;人工智能的应用前景究竟如何&#xff1f;它…

【消息队列】RabbitMQ实现消费者组机制

目录 1. RabbitMQ 的 发布订阅模式 2. GRPC 服务间的实体同步 2.1 生产者服务 2.2 消费者服务 3. 可靠性 3.1 生产者丢失消息 3.2 消费者丢失消息 3.3 RabbitMQ 中间件丢失消息 1. RabbitMQ 的 发布订阅模式 https://www.rabbitmq.com/tutorials/tutorial-three-go P 生…

winUI3 c++ 入门 2、 样式

目录 一、winUI3 基本概念及样式 1、边距 2、如何使用样式 1)、布局控件内定义样式 2)、APP.xmal定义全局样式 3)、单独的样式文件 3.1)、新增字典资源 xmal 3.2)、在里面设置样式 3.3)、引用样式 3、更多样式修改 1)、修改默认属性 2)、修改所有的默认颜色…

垃圾收集器与内存分配机制(一)

目录 一、为什么我们要去了解垃圾收集和内存分配 二、对象已死&#xff1f; 1. 引用计数算法 2. 可达性分析算法 3. 再谈引用 4. 生存还是死亡 5. 回收方法区 三、垃圾收集算法 1. 简介 2. 分代收集理论 2.1. 弱分代/强分代假说 2.2. 前面两代假说的缺陷 3. 标记-清…

智能去毛刺:2D视觉引导机器人如何重塑制造业未来

机器人技术已经深入到各个工业领域中&#xff0c;为制造业带来了前所未有的变革。其中&#xff0c;2D视觉引导机器人技术以其精准、高效的特点&#xff0c;在去毛刺工艺中发挥着越来越重要的作用。本文将为您介绍2D视觉引导机器人技术的基本原理及其在去毛刺工艺中的应用&#…

blender 理解 积木组合 动画制作 学习笔记

一、学习blender视频教程链接 案例2&#xff1a;积木组合_动画制作_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Bt4y1E7qn?vd_sourced0ea58f1127eed138a4ba5421c577eb1&p10&spm_id_from333.788.videopod.episodes 二、说明 之前已经学习了如何制作积木组…

20 Shell Script输入与输出

标出输入、标准输出、错误输出 一、程序的基本三个IO流 一&#xff09;文件描述符 ​ 任何程序在Linux系统中都有3个基本的文件描述符 ​ 比如: ​ cd/proc/$$/fd ​ 进入当前shell程序对于内核在文件系统的映射目录中: [rootlocalhost ~]# cd /proc/$$/fd [rootlocalhos…

Ubuntu22.04环境搭建MQTT服务器

官网&#xff1a; https://mosquitto.org 1.引入库 sudo apt-add-repository ppa:mosquitto-dev/mosquitto-ppa2.升级安装工具 sudo apt-get update 3.安装 sudo apt-get install mosquitto 4.安装客户端 sudo apt-get install mosquitto-clients5.添加修改配置文件 进…

微信小程序上传图片添加水印

微信小程序使用wx.chooseMedia拍摄或从手机相册中选择图片并添加水印&#xff0c; 代码如下&#xff1a; // WXML代码&#xff1a;<canvas canvas-id"watermarkCanvas" style"width: {{canvasWidth}}px; height: {{canvasHeight}}px;"></canvas&…

【Linux】冯诺依曼体系结构 OS的概念

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 主厨&#xff1a;邪王真眼 主厨的主页&#xff1a;Chef‘s blog 所属专栏&#xff1a;青果大战linux 总有光环在陨落&#xff0c;总有新星在闪烁 前言废话&#xff1a…

将java项目jar包打包成exe服务

1.结构展示 2.注意事项 前提: 环境准备:jdk8 和 .net支持 { 1.控制面板》程序和功能》启用和关闭windows功能》.net的勾选》2.jdk8自行百度安装环境3.其他项目必须的软件环境安装等&#xff08;数据库...&#xff09; }第一次准备: 1.将打包好的jar包放到premiumServices.exe…

销冠教你如何转化观望客户

在销售实践中&#xff0c;常会遇到这样的场景&#xff1a;客户对我们的提案表现出极大的兴趣&#xff0c;但在执行阶段却显得迟疑&#xff0c;频繁表示“还需观望&#xff0c;再考虑”。这种态度不仅拖慢了项目进度&#xff0c;甚至可能导致项目完全停滞&#xff0c;从而错失宝…

Spring Boot技术栈在论坛网站开发中的应用

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

FLUX.1-dev-LoRA模型:用一张卡通图片总结4张真实人物照片One-Click-Creative-Template

在这个数字时代&#xff0c;创意图像生成正成为我们生活中不可或缺的一部分。Shakker Labs 推出的 FLUX.1-dev-LoRA-One-Click-Creative-Template 为我们带来了一个全新的体验。这款创新的模板模型专为文本生成图像设计&#xff0c;让您能够轻松创造出令人惊艳的照片。 模型功能…

听泉鉴宝在三个月前已布局商标注册!

近日“听泉鉴宝”以幽默的风格和节目效果迅速涨粉至2500多万&#xff0c;连线出现“馆藏文物”和“盗墓现场”等内容&#xff0c;听泉鉴宝早在几个月前已布局商标注册。 据普推知产商标老杨在商标局网站检索发现&#xff0c;“听泉鉴宝”的主人丁某所持股的江苏灵匠申请了三十…

qt QNetworkProxy详解

一、概述 QNetworkProxy通过设置代理类型、主机、端口和认证信息&#xff0c;可以使应用程序的所有网络请求通过代理服务器进行。它支持为Qt网络类&#xff08;如QAbstractSocket、QTcpSocket、QUdpSocket、QTcpServer、QNetworkAccessManager等&#xff09;配置网络层代理支持…

mysql innodb 引擎如何直接复制数据库文件?

mysql innodb 引擎如何直接复制数据库文件&#xff1f;介绍如下&#xff1a; 1、首先找到数据库文件所在位置 一般可以看my.conf/my.ini配置的文件的“datadir” 看示例&#xff1a; “MAMP”在Macos下的数据库文件位置&#xff1a; /Library/Application Support/appsolu…

展会亮点回顾|HMS汽车工业通信解决方案

2024 汽车测试及质量监控博览会&#xff08;中国&#xff09;&#xff08;Testing Expo China – Automotive&#xff09;于 8 月 28 日至 30 日在上海世博展览馆顺利举行。作为汽车测试技术领域的顶级盛会&#xff0c;来自全球的行业领袖和技术专家齐聚一堂&#xff0c;共同探…