通用vue组件化首页

news2025/1/8 17:57:20

一、首先先建立文件main.vue,构建主体

1.选择合适的模板element-plus,直接复制

2.编写相应的样式

<template>
  <div class="main">
    <el-container class="main-content">
      <el-aside> aside </el-aside>
      <el-container class="page">
        <el-header class="page-header"> header </el-header>
        <el-main class="page-content"> main </el-main>
      </el-container>
    </el-container>
  </div>
</template>
<script lang="ts">
import { defineComponent } from "vue"
export default defineComponent({})
</script>
<style scoped lang="less">
.main {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
.main-content,
.page {
  height: 100%;
}
.page-content {
  height: calc(100%-48px);
}
.page-info {
  background-color: #fff;
  border-radius: 5px;
}
.el-header.el-footer {
  display: inline;
  color: #333;
  text-align: center;
  align-items: center;
}
.el-header {
  height: 48px !important;
}
.el-aside {
  overflow-x: hidden;
  overflow-y: auto;
  line-height: 200px;
  text-align: left;
  cursor: pointer;
  background-color: #001529;
  transition: width 0.3s linear;
  scrollbar-width: none; /* firefox */
  -ms-overflow-style: none; /* IE 10+ */

  &::-webkit-scrollbar {
    display: none;
  }
}
.el-main {
  color: #333;
  text-align: center;
  background-color: #f0f2f5;
}
</style>

二、利用组件化思想,将菜单栏,头部和中间内容分别写成三个文件

1.先建立nav-header和nav-menu文件夹,然后在里面编写主要代码,然后在index,ts里面导出组件

2.然后在main.vue里面对应的aside和header的位置引用上面创建的相应组件

 3.在nav-menu里面写菜单导航

(1)先去找合适的element-plus样式复制

(2)给每个菜单栏一个点击事件,跳转到对应的路由页面

nav-menu.vue

 4.在nav-header.vue设计一个折叠的按钮。可以实现点击折叠菜单栏

(1)先定义一个按钮,并且给按钮一个点击事件,在点击事件里面负责将foldChange事件传给父组件 

(2)然后将点击事件传给引用他的父组件main.vue

 (3)然后父组件里面将接受到的值赋给另一个新变量isCollapse,然后 将这个新的变量值传给子组件nav-menu,同时isCollapse也会响应式改变,从而改变el-aside的宽度

(4)子组件nav-menu在菜单栏el-menu(这个是el-menu的一个属性)接收新变量值,然后实现折叠效果

 

三、nav-header的面包屑和个人信息组件的设计

1.首先是先定义好面包屑和个人信息的位置和相应的样式

<template>
  <div class="nav-header">
    <button @click="handleFoldclick" class="fole-menu">折叠</button>
    <div class="content">
      <div>面包屑</div>
      <div>个人信息</div>
    </div>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref, computed } from "vue"

// import { Expand } from '@element-plus/icons-vue'
export default defineComponent({
  emits: ["foldChange"],

  setup(props, { emit }) {
    const isFold = ref(false)
    const handleFoldclick = () => {
      isFold.value = !isFold.value
      emit("foldChange", isFold.value)
    }
    return {
      isFold,
      handleFoldclick
    }
  }
})
</script>
<style scoped>
.nav-header {
  display: flex;
  width: 100%;
  text-align: center;
  margin-top: 10px;
}
.fold-menu {
  width: 30px;
  height: 20px;
  cursor: pointer;
  margin: 10px;
}
.content {
  /* 自己内部flex布局,两端 */
  display: flex;
  justify-content: space-between;
  /* 在大的nav-header里面flex */
  flex: 1;
  padding: 0 20px;
}
</style>

 2.可以将个人信息单独抽离出来当一个组件user-info.vue,然后再在nav-header对应的个人信息的位置引用user-info组件

user-info.vue

<template>
  <div class="user-info">
    <el-dropdown>
      <span class="el-dropdown-link">
        Dropdown List
        <el-icon class="el-icon--right">
          <arrow-down />
        </el-icon>
      </span>
      <template #dropdown>
        <el-dropdown-menu>
          <el-dropdown-item>Action 1</el-dropdown-item>
          <el-dropdown-item>Action 2</el-dropdown-item>
          <el-dropdown-item>Action 3</el-dropdown-item>
          <el-dropdown-item disabled>Action 4</el-dropdown-item>
          <el-dropdown-item divided>Action 5</el-dropdown-item>
        </el-dropdown-menu>
      </template>
    </el-dropdown>
  </div>
</template>
<script>
import { defineComponent, computed } from "vue"

export default defineComponent({})
</script>
<style scoped></style>

nav-header.vue

<template>
  <div class="nav-header">
    <button @click="handleFoldclick" class="fole-menu">折叠</button>
    <div class="content">
      <div>面包屑</div>
      <user-info></user-info>
    </div>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref, computed } from "vue"
import UserInfo from "./user-info.vue"

export default defineComponent({
  components: {
    UserInfo
  },
  emits: ["foldChange"],

  setup(props, { emit }) {
    const isFold = ref(false)
    const handleFoldclick = () => {
      isFold.value = !isFold.value
      emit("foldChange", isFold.value)
    }
    return {
      isFold,
      handleFoldclick
    }
  }
})
</script>
<style scoped>
.nav-header {
  display: flex;
  width: 100%;
  text-align: center;
  margin-top: 10px;
}
.fold-menu {
  width: 30px;
  height: 20px;
  cursor: pointer;
  margin: 10px;
}
.content {
  /* 自己内部flex布局,两端 */
  display: flex;
  justify-content: space-between;
  /* 在大的nav-header里面flex */
  flex: 1;
  padding: 0 20px;
}
</style>

 3.将登录后的用户名显示在个人信息头像旁边

(1)如果直接把登录后存储在vuex里面的loginInfo直接拿出来赋值给当前user-info里面的变量,虽然可以实现显示用户名,但是会出现一个bug,刷新之后获取不到当前登录的用户信息

(2)如果发生这样的情况,需要将实时将存储在localCache里面的loginInfo拿出来赋值

四、面包屑的设计

1.由于这里的菜单导航不是从接口获取到的,是自定义的,所以这里需要拿到当前的路由的meta里面的title进行匹配显示

2.重新创建一个组件文件breadcrumb.vue,在这个文件里面去使用element-plus里面的面包屑组件

3.这里遍历自定义变量list,然后再 根据当前的路由路经去显示对应的页面

breadcrumb.vue

<template>
  <div class="nav-breadcrumb">
    <el-breadcrumb separator>
      <el-breadcrumb-item v-for="item in list" :key="item.path">
        <router-link :to="{ path: item.path }">
          {{ item.meta.title }}
        </router-link>
      </el-breadcrumb-item>
    </el-breadcrumb>
  </div>
</template>
<script lang="ts">
import { defineComponent, PropType, computed } from "vue"
import { IBreadcrumb } from "../types"
import { useRouter } from "vue-router"
export default defineComponent({
  // props: {
  //   breadcrumbs: {
  //     type: Array as PropType<IBreadcrumb[]>,
  //     default: () => []
  //   }
  // }
  setup() {
    const router = useRouter()
    let list = computed(() => {
      return router.currentRoute.value.matched
    })

    return {
      list
    }
  }
})
</script>

nav-menu.vue

这里也解决了当刷新页面时,导航栏和右侧页面不匹配的问题,这里主要是修改index和default-active

<template>
  <div class="nav-menu">
    <div class="logo">
      <img class="img" src="~@/assets/img/logo.svg" alt="logo" />
      <span class="title" v-if="!collapse">Vue3+TS</span>
    </div>
    <div>
      <el-menu
        :default-active="activeIndex"
        class="el-menu-vertical"
        :collapse="collapse"
      >
        <el-menu-item index="/main/system" @click="handleChartClick">
          <el-icon>
            <House />
          </el-icon>
          <span>系统首页</span>
        </el-menu-item>
        <el-sub-menu index="/main/">
          <template #title>
            <el-icon>
              <User />
            </el-icon>
            <span>商品管理</span>
          </template>
          <el-menu-item index="/main/category" @click="handleUserClick">
            <el-icon>
              <Menu />
            </el-icon>
            商品中心
          </el-menu-item>
          <el-menu-item index="/main/goods" @click="handleAdminUserClick">
            <el-icon>
              <Menu />
            </el-icon>
            商品信息
          </el-menu-item>
        </el-sub-menu>
        <el-menu-item index="/main/order" @click="handleQuestionClick">
          <el-icon>
            <Document />
          </el-icon>
          <span>订单管理</span>
        </el-menu-item>
      </el-menu>
    </div>
  </div>
</template>
<script lang="ts">
import { defineComponent, computed, ref } from "vue"
// import { useStore } from "@/store"
import { useRouter, useRoute } from "vue-router"
// 使用 document.documentElement.style 实现换肤功能
document.documentElement.style.setProperty(`--el-menu-bg-color`, "transparent")

export default defineComponent({
  props: {
    collapse: {
      type: Boolean,
      default: false
    }
  },
  setup() {
    const router = useRouter()
    const activeIndex = ref("")
    // 因为这次是匹配的子路由 所以不需要做处理
    activeIndex.value = router.currentRoute.value.path

    console.log(activeIndex.value)
    const handleUserClick = () => {
      router.push({ path: "/main/category" })
    }
    const handleAdminUserClick = () => {
      router.push({ path: "/main/goods" })
    }
    const handleQuestionClick = () => {
      router.push({ path: "/main/order" })
    }

    const handleChartClick = () => {
      router.push({ path: "/main/system" })
    }

    return {
      // handleHomeClick,
      handleUserClick,
      handleAdminUserClick,
      handleQuestionClick,
      handleChartClick,
      activeIndex
      // handleQuestionClick2
    }
  }
})
</script>
<style scoped lang="less">
.nav-menu {
  height: 100%;

  .logo {
    display: flex;
    height: 28px;
    padding: 12px 10px 8px 10px;
    flex-direction: row;
    justify-content: flex-start;
    align-items: center;
  }
  img {
    height: 100%;
    margin: 0 10px;
  }
  .title {
    font-size: 16px;
    font-weight: 700;
    color: white;
  }
}
// 目录
.el-sub-menu {
  // 二级菜单 ( 默认背景 )
  .el-menu-item {
    padding-left: 50px !important;
    background-color: transparent !important;
    color: #ccc;
  }
}
.el-menu {
  border-right: none;
}

.el-menu-item {
  color: #ccc;
}

.el-sub-menu {
  .el-menu-item {
    padding-left: 50px !important;
    /* background-color: transparent !important; */
    color: #ccc;
  }
}

::v-deep .el-sub-menu__title {
  background-color: transparent !important;
  color: #ccc;
}

// hover 高亮

.el-menu-item:hover {
  color: #20a0ff !important; // 菜单
  background-color: #2c394c !important;
}

.el-menu-item.is-active {
  color: #20a0ff !important;
  background-color: #2c394c !important;
}

.el-menu-vertical:not(.el-menu--collapse) {
  width: 100%;
  height: 100%;
  // height: calc(100% - 48px);
}

a {
  text-decoration: none;
}
</style>

nav-header.vue

<template>
  <div class="nav-header">
    <button @click="handleFoldclick" class="fole-menu">折叠</button>
    <div class="content">
      <hy-breadcrumb></hy-breadcrumb>
      <user-info></user-info>
    </div>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref, computed } from "vue"
import UserInfo from "./user-info.vue"
import HyBreadcrumb, { IBreadcrumb } from "@/base-ui/breadcrumb"

export default defineComponent({
  components: {
    UserInfo,
    HyBreadcrumb
  },
  emits: ["foldChange"],

  setup(props, { emit }) {
    const isFold = ref(false)
    const handleFoldclick = () => {
      isFold.value = !isFold.value
      emit("foldChange", isFold.value)
    }

    return {
      isFold,
      handleFoldclick
    }
  }
})
</script>
<style scoped>
.nav-header {
  display: flex;
  width: 100%;
  text-align: center;
  margin-top: 10px;
}
.fold-menu {
  width: 30px;
  height: 20px;
  cursor: pointer;
  margin: 10px;
}
.content {
  /* 自己内部flex布局,两端 */
  display: flex;
  justify-content: space-between;
  /* 在大的nav-header里面flex */
  flex: 1;
  padding: 0 20px;
  align-items: center;
  text-align: center;
}
</style>

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

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

相关文章

2022年中职组网络安全竞赛D模块竞赛漏洞报告单总结

Windows加固 后门用户 漏洞发现过程 打开cmd使用net user 看到”hacker”用户,疑似存在后门用户 使用hacker/123456成功登录目标服务器,证明存在后门用户 漏洞加固过程 删除后门用户

HTML与CSS基础(一)—— HTML基础(web标准、开发工具、标签)

目标能够理解HTML的 基本语法 和标签的关系 能够使用 排版标签 实现网页中标题、段落等效果 能够使用 相对路径 选择不同目录下的文件 能够使用 媒体标签 在网页中显示图片、播放音频和视频 能够使用 链接标签 实现页面跳转功能一、基础认知目标&#xff1a;认识 网页组成 和 五…

【Linux】程序的翻译四个阶段(图示详解)

因为淋过雨&#xff0c;所以懂的为别人撑伞&#xff1b;因为迷茫过&#xff0c;所以懂得为别人指路。 我们都知道写好代码后&#xff0c;编译器会帮助我们把代码生成可执行程序&#xff0c;细加了解又会知道程序的生成又分为四步&#xff1a;预处理、编译、汇编、链接。那么这四…

JAVA语言基础语法——异常中的常见方法及抛出异常等练习

Throwable的成员方法定义在最顶级Throwable类中a.实例如下&#xff1a;e.printStackTrace(); 将异常的所有信息红色的字体打印在控制台&#xff0c;不会结束虚拟机&#xff0c;仅仅只是打印的操作。抛出处理throws注意&#xff1a;写在方法定义处&#xff0c;表示声明一个异常&…

DOM(三):鼠标、键盘事件对象

鼠标、键盘事件对象鼠标事件对象键盘事件对象鼠标事件对象 event对象代表事件的状态&#xff0c;和事件相关的一系列信息的集合。现阶段我们主要是用鼠标事件对象MouseEvent和键盘事件对象KeyboardEvent 例如&#xff1a; // 鼠标事件对象 MouseEventdocument.addEventListene…

Android正确的保活方案,不要掉进保活需求死循环陷进

在开始前&#xff0c;还是给大家简单介绍一下&#xff0c;以前出现过的一些黑科技&#xff1a; 大概在6年前Github中出现过一个叫MarsDaemon&#xff0c;这个库通过双进程守护的方式实现保活&#xff0c;一时间风头无两。好景不长&#xff0c;进入 Android 8.0时代之后&#x…

STM32系列单片机标准库移植FreeRTOS V10.4.6详解

文中所用到的资料下载地址 https://download.csdn.net/download/qq_20222919/87370679 最近看正点原子新录制了手把手教你学FreeRTOS的视频教程&#xff0c;看了一下教程发现视频里面讲的是使用HAL移植 FreeRTOS V10.4.6 版本&#xff0c;以前的标准库移植的是FreeRTOS V9.0 版…

关于PostgreSQL JIT Memory-Leak 问题 从 LLVM源码层面来分析

文章目录前言LLVM Types 在 JIT中的使用LLVM Types 设计导致的 PG JIT 内存问题分析解决&#xff1f;前言 之前介绍 PG 的 JIT 实现 时提到 为了性能开启JIT 之后有一个比较严重的内存泄漏问题。现象就是在一个backend 内持续跑大量的 sqllogic 随机复杂查询&#xff0c;能够看…

java 微服务 Nacos配置 feign 网关路由

Nacos配置管理 配置信息我们写有热更新需求的配置就可以了 1.引入Nacos的配置管理客户端依赖&#xff1a; <!--nacos配置管理依赖--> <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config…

HBase基础_1

HBase 注&#xff1a;大家觉得博客好的话&#xff0c;别忘了点赞收藏呀&#xff0c;本人每周都会更新关于人工智能和大数据相关的内容&#xff0c;内容多为原创&#xff0c;Python Java Scala SQL 代码&#xff0c;CV NLP 推荐系统等&#xff0c;Spark Flink Kafka Hbase Hive…

学习笔记6:字符串库函数(下)

目录 一. strstr模拟实现 二. strtok模拟实现 三.关于strerror和perror的说明 一. strstr模拟实现 库函数strstr函数首部&#xff1a;char * strstr ( const char *str1, const char * str2); 函数的功能是在str1指向的主字符串中寻找子串str2&#xff0c;并且返回主字符串中…

JS数组对象——英文按照首字母进行排序sort()、localeCompare()

JS数组对象——英文按照首字母进行排序(sort、localeCompare&#xff09;上期回顾场景复现sort()方法与localeCompare实例应用上期回顾 文章内容文章链接JS数组对象——根据日期进行排序Date.parse()&#xff0c;按照时间进行升序或降序排序https://blog.csdn.net/XSL_HR/arti…

【CANN训练营第三季】AI目标属性编辑应用

文章目录1、参考样例进行运行stargan2、dvpp媒体数据处理结业考核题目1、题目2、题目31、参考样例进行运行stargan 下载stargan后&#xff0c;查看readme&#xff0c;进行复现。 # 为了方便下载&#xff0c;在这里直接给出原始模型下载及模型转换命令,可以直接拷贝执行。 cd …

Tic-Tac-Toe:基于Minimax算法的人机对弈程序(python实现)

目录 1. 前言 2. Minimax算法介绍 2.1 博弈树 2.2 估值函数 2.3 基本算法思想 2.4 实例1 ​​​​​​​2.5 实例2—棋类游戏 2.6 小结 3. Tic-Tac-Toe minimax AI实现 3.1 函数说明 3.2 处理流程 3.3 代码 4. 小结 1. 前言 在上一篇中实现一个简单的Tic-Tac-Toe人…

【07】概率图推断之信念传播

概率图推断之信念传播 文章目录将变量消除视为信息传递信息传递算法加总乘积信息传递因子树上的加总乘积信息传递最大乘积信息传递总结在《概率图推断之变量消除算法》中&#xff0c;我们讲了变量消除算法如何对有向图和无向图求P(Y∣Ee)P(Y \mid E e)P(Y∣Ee)的边缘概率。 …

java 微服务之MQ 异步通信

初识MQ 同步调用存在的问题 异步调用常见实现就是事件驱动模式 事件驱动模式优势&#xff1a; 优势1&#xff1a;服务解耦 一旦有新业务只需要订阅或者减少事件就行了 优势2&#xff1a;性能提升&#xff0c;吞吐量提高 优势3&#xff1a;服务没有强依赖&#xff0c;不用担…

【自学C++】C++注释

C注释 C注释教程 用于注解说明解释程序的文字就是注释&#xff0c;注释提高了代码的阅读性。同时&#xff0c;注释也是一个程序员必须要具有的良好编程习惯。我们应该首先将自己的思想通过注释先整理出来&#xff0c;再用代码去体现。 在 C 中&#xff0c;一旦程序中某部分内…

数据结构和算法-计数排序

1.算法描述 技术排序是一个基于比较的排序算法&#xff0c;该算法于1954由Harold H. Seward 提出。它的优势在于对 一定范围内的整数排序时&#xff0c;它的复杂度为O&#xff08;nk&#xff09;&#xff08;其中k是整数的范围&#xff09;&#xff0c;快于任何比较排序算 法…

JavaEE高阶---Spring事务和事务传播机制

一&#xff1a;什么是事务&#xff1f; 事务定义&#xff1a;将⼀组操作封装成⼀个执⾏单元&#xff08;封装到⼀起&#xff09;&#xff0c;要么全部成功&#xff0c;要么全部失败。 二&#xff1a;Spring中事务的实现 编程式事务&#xff08;⼿动写代码操作事务&#xff09…

使用 Flink CDC 实现 MySQL 数据实时入 Apache Doris

简介 主要内容如下&#xff1a; MySQL 安装和开启binogFlink环境准备Apache Doris 环境准备启动Flink CDC作业 1. MySQL 安装和开启binog 参考文章&#xff1a;Ubuntu 安装 Mysql server, 这篇文章介绍了MySQL的安装&#xff0c;用户创建&#xff0c;Binlog开启等内容。 M…