vue组件开发:构建响应式快捷导航

news2025/3/1 11:46:10

前言

快捷导航不仅能够显著提升系统的灵活性和用户交互性,还极大地增强了用户的操作体验。本文将展示如何在 vue 中实现一个既可自定义又具备响应式特性的快捷导航菜单。


一、实现思路

列表页

  • 结构设计

    定义页面结构,包含一个导航卡片和一个对话框组件;
    导航卡片中包含一个标题、添加按钮和导航项列表;
    使用 v-for 指令遍历 routeData 数组,动态生成每个导航项。

  • 数据管理

    data 中定义 routeData 数组,存储导航项的信息(如图标和标题);
    定义 dialogChild 变量,用于控制对话框的显隐状态。

  • 事件处理

    handleCellClick(item):处理点击导航项的事件,输出所点击的项的信息;
    deleteItem(index):处理删除导航项的事件,通过 splice 方法从 routeData 中移除指定项;
    navigationAdd():打开添加导航项的对话框,将 dialogChild 设置为 true

1.1 列表组件

<template>
  <div class="navigation">
    <div class="cardContent">
      <el-card class="box-card">
        <div slot="header">
          <span />
          <span class="cardName">快捷导航</span>
          <el-link style="float: right" type="primary" @click="navigationAdd">添加</el-link>
        </div>
        <div v-if="routeData && routeData.length" class="gridContainer">
          <!-- 遍历路由数据,生成每个导航项 -->
          <div v-for="(item, index) in routeData" :key="index" class="gridContent">
            <div class="content" :title="item.title" @click.stop="handleCellClick(item)">
              <p><img :src="item.imgUrl" alt="" /></p>
              <p>{{ item.title }}</p>
            </div>
            <div class="overlay">
              <i title="删除" class="el-icon-circle-close" @click.stop="deleteItem(index)"></i>
            </div>
          </div>
        </div>
        <div v-else><el-empty description="暂无数据"></el-empty></div>
      </el-card>
    </div>
    <navigation-dialog :dialogChild.sync="dialogChild" />
  </div>
</template>

<script>
import NavigationDialog from "./navigationDialog.vue";
export default {
  components: { NavigationDialog },
  data() {
    return {
      dialogChild: false, // 控制对话框显隐状态
      routeData: [
        //模拟数据
        {
          imgUrl: require("../assets/demo.png"),
          title: "数据统计",
        },
        {
          imgUrl: require("../assets/demo.png"),
          title: "订单管理",
        },
        {
          imgUrl: require("../assets/demo.png"),
          title: "汇总信息",
        },
        {
          imgUrl: require("../assets/demo.png"),
          title: "客服管理",
        },
        {
          imgUrl: require("../assets/demo.png"),
          title: "财物中心",
        },
        {
          imgUrl: require("../assets/demo.png"),
          title: "系统管理",
        },
        {
          imgUrl: require("../assets/demo.png"),
          title: "系统监控",
        },
        {
          imgUrl: require("../assets/demo.png"),
          title: "系统工具",
        },
      ],
    };
  },
  methods: {
    // 点击导航项的处理函数
    handleCellClick(item) {
      console.log("item:", item);
    },
    // 删除导航项的处理函数
    deleteItem(index) {
      this.routeData.splice(index, 1);
    },
    // 打开添加导航项对话框的处理函数
    navigationAdd() {
      this.dialogChild = true;
    },
  },
};
</script>

<style lang="less" scoped>
.navigation {
  width: 36%;
  padding: 16px;
  .cardContent {
    span:first-child {
      display: inline-block;
      width: 10px;
      height: 10px;
      background: #409eff;
      margin-right: 10px;
    }
    .cardName,
    .el-link {
      font-weight: bold;
    }
    .gridContainer {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
      gap: 16px;
      padding: 16px;
      .gridContent {
        width: 100px;
        height: 100px;
        border-radius: 4px;
        position: relative;
        box-sizing: border-box;
        overflow: hidden;
        background: linear-gradient(to bottom, rgba(106, 183, 255, 0.7), rgba(106, 183, 255, 0.2));
        display: flex;
        align-items: center;
        justify-content: center;
        text-align: center;
        .content {
          cursor: pointer;
          color: rgb(60, 60, 60);
          img {
            width: 50px;
            height: 50px;
          }
          p:nth-child(2) {
            margin-top: 2px;
            width: 92px;
            padding: 0px 4px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
          }
        }
      }
      .overlay {
        position: absolute;
        top: 3px;
        right: 3px;
      }
      .el-icon-circle-close {
        cursor: pointer;
        font-size: 18px;
        color: rgb(255, 255, 255);
      }
      .el-icon-circle-close:hover {
        color: rgba(255, 255, 255, 0.5);
      }
    }
  }
}
::v-deep {
  .el-checkbox-button__inner {
    margin: 0 8px 10px 8px;
    border: 1px solid #d3d3d3;
    border-radius: 4px !important;
  }
}
</style>

弹框页

  • 结构设计

    使用 <el-dialog> 组件创建一个对话框,包含标题和内容区域;
    在内容区域中,使用 v-for 遍历 cities 数组,生成每个菜单的选项和复选框。

  • 数据管理

    data 中定义 cities 数组,模拟系统管理和监控等菜单项;
    定义 checkStates 对象,用于存储每个菜单的选中状态(全选、部分选中和选中的城市)。

  • 事件处理

    initializeCheckStates():初始化每个菜单的选中状态,设置全选状态和选中的菜单;
    handleCheckAllChange(item):处理全选复选框的变化,更新选中状态;
    handleCheckedCitiesChange(item):处理菜单复选框的变化,更新全选和部分选中状态;
    submit():提交选中的信息,过滤出选中的路由项,并输出到控制台;
    cancel():取消操作,重置选中状态并关闭对话框。

2.1 弹框组件

<template>
  <el-dialog :close-on-click-modal="false" title="添加快捷导航" width="60%" :visible.sync="dialogVisible" @close="cancel">
    <el-card class="box-card">
      <!-- 遍历菜单数组,生成每个菜单的选项 -->
      <div v-for="(item, index) in cities" :key="index" class="checkboxContent">
        <span class="navTit">{{ item.label }}</span>
        <!-- 全选复选框 -->
        <el-checkbox v-model="checkStates[item.label].checkAll" :indeterminate="checkStates[item.label].isIndeterminate" @change="handleCheckAllChange(item)">全选</el-checkbox>
        <!-- 菜单的复选框组 -->
        <el-checkbox-group v-model="checkStates[item.label].checkedCities" size="medium" @change="handleCheckedCitiesChange(item)">
          <el-checkbox-button v-for="(e, isx) in item.router" :key="isx" :label="e.title" border>{{ e.title }}</el-checkbox-button>
        </el-checkbox-group>
      </div>
      <div class="btns">
        <el-button size="medium" type="primary" @click="submit">保 存</el-button>
        <el-button size="medium" @click="cancel">取 消</el-button>
      </div>
    </el-card>
  </el-dialog>
</template>
<script>
export default {
  props: {
    dialogChild: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      dialogVisible: false, // 控制对话框显隐状态
      cities: [
        //模拟数据
        {
          label: "系统管理",
          router: [
            { title: "用户管理", id: 0 },
            { title: "角色管理", id: 1 },
            { title: "菜单管理", id: 2 },
            { title: "部门管理", id: 3 },
            { title: "日志管理", id: 4 },
            { title: "字典管理", id: 5 },
          ],
        },
        {
          label: "系统监控",
          router: [
            { title: "在线用户", id: 6 },
            { title: "定时任务", id: 7 },
          ],
        },
        {
          label: "系统工具",
          router: [{ title: "表单构建", id: 8 }],
        },
      ],
      checkStates: {}, // 存储每个菜单的选中状态
    };
  },
  watch: {
    dialogChild: {
      handler(newName) {
        this.dialogVisible = newName;
      },
      deep: true,
    },
  },
  mounted() {
    this.initializeCheckStates();
  },
  methods: {
    // 初始化每个菜单的选中状态
    initializeCheckStates() {
      this.cities.forEach((item) => {
        this.$set(this.checkStates, item.label, {
          checkAll: false, // 全选状态
          checkedCities: [], // 选中的菜单
          isIndeterminate: false, // 是否为部分选中状态
        });
      });
    },
    // 处理全选复选框的变化
    handleCheckAllChange(item) {
      this.checkStates[item.label].checkedCities = this.checkStates[item.label].checkAll ? item.router.map((e) => e.title) : [];
      this.checkStates[item.label].isIndeterminate = false; // 重置部分选中状态
    },
    // 处理菜单复选框的变化
    handleCheckedCitiesChange(item) {
      const checkedCount = this.checkStates[item.label].checkedCities.length; // 选中的菜单数量
      this.checkStates[item.label].checkAll = checkedCount === item.router.length; // 更新全选状态
      this.checkStates[item.label].isIndeterminate = checkedCount > 0 && checkedCount < item.router.length; // 更新部分选中状态
    },
    // 提交选中的信息
    submit() {
      const selectedInfo = this.cities.map((item) => {
        const { checkedCities } = this.checkStates[item.label]; // 获取当前导航项的选中状态
        const selectedRoutes = item.router.filter((route) => checkedCities.includes(route.title)); // 过滤出选中的路由项
        return {
          label: item.label, // 导航项标签
          selectedRoutes: selectedRoutes.map((route) => ({
            title: route.title,
            id: route.id,
          })), // 选中的路由项
        };
      });
      console.log("选中的信息:", selectedInfo); // 输出选中的信息
    },
    // 取消操作
    cancel() {
      this.initializeCheckStates(); // 重置选中状态
      this.$emit("update:dialogChild", false);
    },
  },
};
</script>

<style lang="less" scoped>
.checkboxContent {
  margin-bottom: 16px;
  .navTit {
    margin-right: 10px;
    color: rgb(41, 107, 255);
    font-weight: bold;
    font-size: 16px;
  }
  .el-checkbox {
    margin: 16px 0;
  }
}
.btns {
  margin-top: 16px;
  display: flex;
  justify-content: right;
}
::v-deep {
  .el-checkbox-button__inner:nth-child(n + 2) {
    margin: 0 !important;
    margin: 0 10px 10px 0 !important;
  }
}
</style>

1.3 组件通信

使用 props$emit 实现父子组件之间的通信。A 页面通过 dialogChild 属性控制 B 页面的对话框显隐状态,并通过 update:dialogChild 事件通知 B 页面关闭对话框。


二、实现效果

在这里插入图片描述

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

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

相关文章

基于 Spring Boot 实现图片的服务器本地存储及前端回显

??导读&#xff1a;本文探讨了在网站开发中图片存储的各种方法&#xff0c;包括本地文件系统存储、对象存储服务&#xff08;如阿里云OSS&#xff09;、数据库存储、分布式文件系统及内容分发网络&#xff08;CDN&#xff09;。文中详细对比了这些方法的优缺点&#xff0c;并…

深入了解IPv6——光猫相关设定:DNS来源、DHCPv6服务、前缀来源等

光猫IPv6设置后的效果对比图&#xff1a; 修改前&#xff1a; 修改后&#xff1a; 一、DNS来源 1. 网络连接 来源&#xff1a; 从上游网络&#xff08;如运营商&#xff09;获取 IPv6 DNS 信息&#xff0c;通过 PPPoE 或 DHCPv6 下发。 特点&#xff1a; DNS 服务器地址直…

欧科云链研究院:AI时代,如何证明“我是我”?

OKG Research&#xff5c;编辑 近日&#xff0c;OpenAI 发布了新模型 Sora。这是一款高性能的文本到多模态生成工具&#xff0c;支持从文本生成精细的图像和动态视频。 相较早先发布的视频样例&#xff0c;该功能目前已经可以由用户真实上手体验&#xff0c;目前由于服务过载…

Cesium进阶教程——自定义图形、外观、绘图基础、现有着色器移植至Cesium、ShadowMapping、视频GIS、模型压平、卷帘

基础必看 WEBGL基础&#xff08;从渲染管线角度解读&#xff09; 参考路线 http://www.xt3d.online/tutorial/further/article.html 自定义图形 https://blog.csdn.net/m0_55049655/article/details/138908327 https://blog.csdn.net/m0_55049655/article/details/140306837 …

【Linux|计算机网络】HTTPS工作原理与安全机制详解

目录 1、HTTPS是什么&#xff1f; 2、概念准备 2.1.什么是加密、解密、密钥 2.2.为什么要加密 2.3.常见的加密方式 1.对称加密 2.非对称加密 2.4.数据摘要 && 数据指纹 2.5. 数字签名 3.HTTPS 的工作过程探究 方案 1 - 只使用对称加密 方案 2 - 只使用非对…

【JavaWeb后端学习笔记】Redis常用命令以及Java客户端操作Redis

redis 1、redis安装与启动服务2、redis数据类型3、redis常用命令3.1 字符串String3.2 哈希Hash3.3 列表List3.4 集合Set&#xff08;无序&#xff09;3.5 有序集合zset3.6 通用命令 4、使用Java操作Redis4.1 环境准备4.2 Java操作字符串String4.3 Java操作哈希Hash4.4 Java操作…

洛谷题解P1219 [USACO1.5] 八皇后 Checker Challenge

本题是一道dfs的题目&#xff08;&#xff09;&#xff08;&#xff09;感觉主要的困惑点在于对角线的判断&#xff08;我刚开始还想遍历&#xff09; 题目&#xff1a; 题目很简短&#xff0c;清晰易懂&#xff0c;就是要找到全部的能使n个棋子在不同行不同列并且也不会在同一…

伺服电机控制驱动器选择

伺服电机控制驱动器选择 根据具体使用场景和需求&#xff0c;可以选择 Modbus RTU、Modbus TCP 或 CAN 通信方式。这些协议在伺服电机的驱动和固件中起到核心作用。以下是详细说明及推荐。 1. 驱动器的作用 接收控制器指令&#xff08;如位置、速度或扭矩命令&#xff09;。将…

嵌入式跨平台工具链终极方案

嵌入式跨平台工具链终极方案 1. 解决烦人的编译&#xff0c;从编译器开始2. T0级别的代码编辑器IDE3. git linus之父开发神奇的分布式代码管理工具 我们从8051开始学习嵌入式&#xff0c;用过了不少IDE&#xff0c;比如经典的keil和IAR&#xff0c;但是这些IDE都不便宜&#xf…

Ubuntu安装Gitlab详细图文教程

1、环境准备 1.1、Ubuntu环境 Ubuntu24.04Sever版安装教程 1.2、更新系统 sudo apt update -y sudo apt-get update sudo apt-get upgrade 2、安装Nginx 2.1 安装nginx # 安装 apt install nginx -y 2.2 修改nginx配置⽂件 # 修改nginx配置 vim /etc/nginx/si…

redis集群安装部署 redis三主三从集群

redis集群安装部署 redis三主三从集群 1、下载redis2、安装redis集群 三主三从3、配置redis开机自启动3.1、建立启动脚本3.2、复制多份redis启动脚本给集群使用3.3、添加可执行权限3.4、配置开机自启动 1、下载redis 本次redis安装部署选择当前最新的稳定版本7.4.1 下载链接: …

泊松编辑 possion editing图像合成笔记

开源地址&#xff1a; GitHub - kono-dada/Reproduction-of-possion-image-editing 掩码必须是矩形框

【Linux系列】Linux 系统中查看目录权限

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

6.2 MapReduce工作原理

MapReduce工作原理涉及将大数据集分割成小块并行处理。Map任务读取数据块并输出中间键值对&#xff0c;而Reduce任务则处理这些排序后的数据以生成最终结果。MapTask工作包括读取数据、应用Map函数、收集输出、内存溢出时写入磁盘以及可选的Combiner局部聚合。ReduceTask工作则…

9. 高效利用Excel设置归档Tag

高效利用Excel设置归档Tag 1. Excle批量新建/修改归档Tag2. 趋势记录模型批量导入归档Tag(Method1)2. 趋势记录模型批量导入归档Tag(Method2)3. 趋势记录控件1. Excle批量新建/修改归档Tag Fcatory Talk常常需要归档模拟量,对于比较大的项目工程会有成千上万个重要数据需…

docker 部署 redis

docker 部署 redis 1. 下载 redis 镜像 # docker images | grep redis bitnami/redis 7.2.4-debian-11-r5 45de196aef7e 10 months ago 95.2MB2. docker-compose 部署 version: "3" services:redis:image: bitnami/redis:7.2.4-debian-11-…

基于python绘制数据表(上)

利用python绘制各种数据图表 绘制柱形图-源码 from openpyxl import Workbook from openpyxl.chart import BarChart, Reference# 创建工作薄 wb Workbook(write_onlyTrue) # 创建工作表 ws wb.create_sheet(月收入)# 准备数据 rows [(月份, 销售额),(1, 23),(2, 43),(3, …

使用skywalking,grafana实现从请求跟踪、 指标收集和日志记录的完整信息记录

Skywalking是由国内开源爱好者吴晟开源并提交到Apache孵化器的开源项目&#xff0c; 2017年12月SkyWalking成为Apache国内首个个人孵化项目&#xff0c; 2019年4月17日SkyWalking从Apache基金会的孵化器毕业成为顶级项目&#xff0c; 目前SkyWalking支持Java、 .Net、 Node.js、…

ViG:图像分类领域前沿

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;传知代码 欢迎大家点赞收藏评论&#x1f60a; 目录 图片分类任务方法概述卷积神经网络&#xff08;CNN&#xff09;视觉Transformer&#xff08;ViT&#xff09;视觉图神经网络&#xff08;ViG&a…

系列2:基于Centos-8.6Kubernetes 集成GPU资源信息

每日禅语 自省&#xff0c;就是自我反省、自我检查&#xff0c;自知己短&#xff0c;从而弥补短处、纠正过失。佛陀强调自觉觉他&#xff0c;强调以达到觉行圆满为修行的最高境界。要改正错误&#xff0c;除了虚心接受他人意见之外&#xff0c;还要不忘时时观照己身。自省自悟之…