Vue实现响应式导航菜单:桌面端导航栏 + 移动端抽屉式菜单

在现代Web开发中,为了提升用户体验,响应式设计已成为必备技能。本文将通过Vue.js,创建一个响应式导航菜单,桌面端显示顶部导航栏,移动端则切换为抽屉式菜单,并具备点击遮罩关闭的功能。以下是具体实现步骤。


项目需求分析

我们希望实现以下功能: 1. 桌面端宽屏(大于 768px):顶部导航菜单,水平布局,导航栏固定在页面顶部。 2. 移动端窄屏(小于或等于 768px):隐藏顶部导航栏,显示抽屉式菜单,点击遮罩层或关闭按钮可关闭抽屉。 3. 响应式设计:根据屏幕宽度自动切换布局,实时监听窗口大小变化。


实现步骤

1. 创建 Vue 项目并初始化布局

首先,初始化 Vue 项目。以下是 HTML 模板的基础结构,包含桌面端和移动端的两种菜单形式:

<template><div id="app"><!-- 顶部导航栏(仅桌面端显示) --><header><nav class="top-nav" v-if="!isMobile"><ul class="menu-list"><li v-for="(item, index) in menuItems" :key="index"><a href="#">{{ item.title }}</a></li></ul></nav><!-- 菜单按钮(仅移动端显示) --><button v-if="isMobile" class="menu-button" @click="toggleDrawer">☰</button></header><!-- 抽屉式菜单 --><div class="drawer" :class="{ open: isDrawerOpen }"><div class="drawer-header"><span class="logo">导航菜单</span><button class="close-button" @click="toggleDrawer">×</button></div><ul class="menu-list"><li v-for="(item, index) in menuItems" :key="index"><a href="#">{{ item.title }}</a></li></ul></div><!-- 抽屉遮罩层 --><div v-if="isMobile && isDrawerOpen" class="overlay" @click="closeDrawer"></div></div>
</template>

如果有二级菜单需要去做一些优化修改,使用css鼠标hover显示子级菜单或者通过js控制子级菜单展开折叠,以下是一个vue模版:

<template><div id="app"><!-- 菜单按钮 --><button class="menu-button" @click="toggleDrawer">☰</button><!-- 抽屉菜单 --><div class="drawer" :class="{ open: isDrawerOpen }"><div class="drawer-header"><span class="logo">Blog</span><button class="close-button" @click="toggleDrawer">×</button></div><ul class="menu-list"><li v-for="(item, index) in menuItems" :key="index" class="menu-item"><div class="menu-title" @click="toggleItem(index)"><span>{{ item.title }}</span><span v-if="item.submenu" class="arrow">{{ openIndex === index ? "▲" : "▼" }}</span></div><ul v-if="item.submenu && openIndex === index" class="submenu"><li v-for="(subItem, subIndex) in item.submenu" :key="subIndex">{{ subItem }}</li></ul></li></ul></div></div>
</template>
<script>
export default {data() {return {isDrawerOpen: false, // 抽屉是否打开openIndex: null, // 当前展开的菜单索引menuItems: [{ title: "🏠 首页" },{ title: "📱 科技社", submenu: ["互联网漫谈", "科技动态"] },{ title: "🎁 福利社", submenu: ["优惠活动", "每日抽奖"] },{ title: "🧰 资源社", submenu: ["学习资料", "工具下载"] },{ title: "💬 有话说" },{ title: "👭 友情频道" },{ title: "🍺 关于小站", submenu: ["站点介绍", "联系我们"] },],};},methods: {toggleDrawer() {this.isDrawerOpen = !this.isDrawerOpen; // 切换抽屉状态},toggleItem(index) {// 展开或折叠二级菜单this.openIndex = this.openIndex === index ? null : index;},},
};
</script>
<style scoped>
body {margin: 0;font-family: Arial, sans-serif;
}.menu-button {position: fixed;top: 16px;left: 16px;font-size: 24px;background: none;border: none;cursor: pointer;
}.drawer {position: fixed;top: 0;left: 0;width: 75%;height: 100%;background-color: white;transform: translateX(-100%);transition: transform 0.3s ease;box-shadow: 2px 0 8px rgba(0, 0, 0, 0.2);
}.drawer.open {transform: translateX(0);
}.drawer-header {display: flex;justify-content: space-between;align-items: center;padding: 16px;background-color: #f5f5f5;border-bottom: 1px solid #ddd;
}.logo {font-size: 20px;font-weight: bold;
}.close-button {background: none;border: none;font-size: 24px;cursor: pointer;
}.menu-list {list-style: none;padding: 0;margin: 0;
}.menu-item {padding: 16px;display: flex;flex-direction: column;justify-content: space-between;align-items: center;cursor: pointer;border-bottom: 1px solid #ddd;
}.menu-title {width: 100%;
}.submenu {width: 100%;list-style: none;padding: 0 16px;margin: 0;padding: 0 16px;background-color: #f9f9f9;
}.submenu li {padding: 8px 0;border-bottom: 1px solid #eee;
}.arrow {font-size: 12px;
}
</style>

2. 使用 Vue 管理状态

在脚本部分,我们通过 data 定义了抽屉状态 isDrawerOpen 和当前是否是移动端的标志 isMobile,并通过 methods 处理逻辑,包括菜单开关和窗口大小监听。

<script>
export default {data() {return {isDrawerOpen: false, // 抽屉是否打开isMobile: false,     // 当前是否是移动端menuItems: [{ title: "🏠 首页" },{ title: "📱 科技社" },{ title: "🎁 福利社" },{ title: "🧰 资源社" },{ title: "💬 有话说" },{ title: "👭 友情频道" },{ title: "🍺 关于小站" },],};},methods: {toggleDrawer() {this.isDrawerOpen = !this.isDrawerOpen; // 切换抽屉开关},closeDrawer() {this.isDrawerOpen = false; // 关闭抽屉},checkScreenSize() {this.isMobile = window.innerWidth <= 768; // 判断是否为移动端},},mounted() {this.checkScreenSize(); // 初次加载时检查屏幕尺寸window.addEventListener("resize", this.checkScreenSize); // 监听窗口大小变化},beforeDestroy() {window.removeEventListener("resize", this.checkScreenSize); // 组件销毁时移除监听器},
};
</script>

3. 添加样式

为实现桌面端顶部导航栏和移动端抽屉菜单,我们需要分别设置两种样式。

<style scoped>
/* 通用样式 */
body {margin: 0;font-family: Arial, sans-serif;
}/* 顶部导航栏样式(桌面端) */
.top-nav {position: fixed;top: 0;left: 0;width: 100%;background-color: #f5f5f5;padding: 16px;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);z-index: 1000;
}.top-nav .menu-list {display: flex;justify-content: flex-start;list-style: none;margin: 0;padding: 0;
}.top-nav .menu-list li {margin-right: 20px;
}.top-nav .menu-list li a {text-decoration: none;color: #333;
}/* 移动端抽屉菜单样式 */
.menu-button {font-size: 24px;background: none;border: none;cursor: pointer;
}.drawer {position: fixed;top: 0;left: 0;width: 75%;height: 100%;background-color: white;transform: translateX(-100%);transition: transform 0.3s ease;box-shadow: 2px 0 8px rgba(0, 0, 0, 0.2);z-index: 1000;
}.drawer.open {transform: translateX(0);
}.drawer-header {display: flex;justify-content: space-between;align-items: center;padding: 16px;background-color: #f5f5f5;border-bottom: 1px solid #ddd;
}.menu-list {list-style: none;padding: 0;margin: 0;
}.menu-list li {padding: 16px;border-bottom: 1px solid #ddd;
}.menu-list li a {text-decoration: none;color: #333;
}/* 遮罩层 */
.overlay {position: fixed;top: 0;left: 0;width: 100%;height: 100%;background: rgba(0, 0, 0, 0.5);z-index: 999;
}/* 响应式样式 */
@media (max-width: 768px) {.top-nav {display: none; /* 隐藏桌面端导航 */}
}
</style>

4. 完整代码

整合模板、脚本和样式,完整代码如下:

<template><div id="app"><header><nav class="top-nav" v-if="!isMobile"><ul class="menu-list"><li v-for="(item, index) in menuItems" :key="index"><a href="#">{{ item.title }}</a></li></ul></nav><button v-if="isMobile" class="menu-button" @click="toggleDrawer">☰</button></header><div class="drawer" :class="{ open: isDrawerOpen }"><div class="drawer-header"><span class="logo">导航菜单</span><button class="close-button" @click="toggleDrawer">×</button></div><ul class="menu-list"><li v-for="(item, index) in menuItems" :key="index"><a href="#">{{ item.title }}</a></li></ul></div><div v-if="isMobile && isDrawerOpen" class="overlay" @click="closeDrawer"></div></div>
</template><script>
export default {data() {return {isDrawerOpen: false,isMobile: false,menuItems: [{ title: "🏠 首页" },{ title: "科技社" },{ title: "🎁 福利社" },{ title: "🧰 资源社" },{ title: "💬 北城有话说" },{ title: "✈️ TG订阅频道" },{ title: "🍺 关于小站" },],};},methods: {toggleDrawer() {this.isDrawerOpen = !this.isDrawerOpen;},closeDrawer() {this.isDrawerOpen = false;},checkScreenSize() {this.isMobile = window.innerWidth <= 768;},},mounted() {this.checkScreenSize();window.addEventListener("resize", this.checkScreenSize);},beforeDestroy() {window.removeEventListener("resize", this.checkScreenSize);},
};
</script><style scoped>
/* 样式同上 */
</style>

运行效果

  1. 桌面端:显示水平导航菜单,固定在页面顶部。
  2. 移动端:显示抽屉式菜单,点击按钮展开,点击遮罩关闭。

通过这个例子,我们实现了一个功能完备、易于扩展的响应式导航菜单,你可以根据需求进一步美化样式或添加其他功能!

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

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

相关文章

GCP Cloud Storage 的lock retention policy是什么

简介 Google Cloud Storage 的锁定保留策略&#xff08;Lock Retention Policy&#xff09;是一种用于保护存储桶中对象数据的功能。它允许用户设置一个保留期&#xff0c;在此期间对象不能被删除或覆盖。这对于确保数据的长期保留和合规性非常重要&#xff0c;尤其是在需要满…

STM32设计防丢防摔智能行李箱

目录 目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 1.电路图采用Altium Designer进行设计&#xff1a; 2.实物展示图片 三、程序源代码设计 四、获取资料内容 前言 随着科技的不断发展&#xff0c;嵌入式系统、物联网技术、智能设备…

CSP/信奥赛C++语法基础刷题训练(11):洛谷P5743:猴子吃桃

CSP/信奥赛C语法基础刷题训练&#xff08;11&#xff09;&#xff1a;洛谷P5743&#xff1a;猴子吃桃 题目描述 一只小猴买了若干个桃子。第一天他刚好吃了这些桃子的一半&#xff0c;又贪嘴多吃了一个&#xff1b;接下来的每一天它都会吃剩余的桃子的一半外加一个。第 n n n…

控制器ThinkPHP6

五、控制器中对数组值的返回 在做接口服务时&#xff0c;很多时候回使用数组作为返回值&#xff0c;那么数组如何返回成 json呢&#xff1f; 在 tp6 中返回json 很简单&#xff0c;直接使用 json 进行返回即可&#xff0c;例如&#xff1a; public function index(){$resarra…

洛谷刷题日记||基础篇8

#include <iostream> #include <vector> using namespace std;int N, M; // N为行数&#xff0c;M为列数 vector<vector<char>> field; // 表示田地的网格&#xff0c;每个元素是W或. vector<vector<bool>> visited; // 用来记录网格是否访…

随机森林(Random Forest, RF)筛选回归数据(处理异常值)

下面是一个完整的 MATLAB 代码示例&#xff0c;用于实现随机森林&#xff08;Random Forest, RF&#xff09;回归&#xff0c;执行 5 折交叉验证&#xff0c;并根据预测误差删除误差较大的行&#xff0c;将处理后的数据保存为新的 Excel 文件。 % 导入数据 data readmatrix(d…

Qwen2.5-3B-Instruct-GGUF部署

注册账号&#xff1a; 魔搭社区 等一会&#xff1a; 部署好了&#xff1a; 立即使用&#xff1a; 您部署的服务提供OpenAI API接口&#xff0c;可通过OpenAI SDK进行调用。请确保您的服务处于正常运行状态&#xff0c;并预先安装OpenAI SDK: pip install openai 在本地新建…

微信小程序进行md5加密 ,base64 转码

封装一个Md5加密的工具 &#xff1a; utils /md5.js function md5(string) { function md5_RotateLeft(lValue, iShiftBits) { return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)); } function md5_AddUnsigned(lX, lY) { var lX4, lY4, l…

服务器虚拟化技术深度解析及代码应用案例

服务器虚拟化技术深度解析及代码应用案例 在现代数据中心和云计算环境中&#xff0c;服务器虚拟化技术已经成为提高资源利用率、降低成本和简化管理的重要手段。本文将详细介绍服务器虚拟化的基本概念、主要类型、技术特性、应用优势&#xff0c;并通过一个基于Golang的容器化…

深入解析Python中的逻辑回归:从入门到精通

引言 在数据科学领域&#xff0c;逻辑回归&#xff08;Logistic Regression&#xff09;是一个非常重要的算法&#xff0c;它不仅用于二分类问题&#xff0c;还可以通过一些技巧扩展到多分类问题。逻辑回归因其简单、高效且易于解释的特点&#xff0c;在金融、医疗、广告等多个…

恶意PDF文档分析记录

0x1 PDF是什么 PDF&#xff08;便携式文件格式&#xff0c;Portable Document Format&#xff09;是由Adobe Systems在1993年用於文件交换所发展出的文件格式。 因为PDF的文件格式性质广泛用于商业办公&#xff0c;引起众多攻击者对其开展技术研究&#xff0c;在一些APT&#…

Spring-事务学习

spring事务 1. 什么是事务? 事务其实是一个并发控制单位&#xff0c;是用户定义的一个操作序列&#xff0c;这些操作要么全部完成&#xff0c;要不全部不完成&#xff0c;是一个不可分割的工作单位。事务有 ACID 四个特性&#xff0c;即&#xff1a; 原子性&#xff08;Atom…

CVE-2024-2961漏洞的简单学习

简单介绍 PHP利用glibc iconv()中的一个缓冲区溢出漏洞&#xff0c;实现将文件读取提升为任意命令执行漏洞 在php读取文件的时候可以使用 php://filter伪协议利用 iconv 函数, 从而可以利用该漏洞进行 RCE 漏洞的利用场景 PHP的所有标准文件读取操作都受到了影响&#xff1…

[Kotlin标准函数] run、with、apply、also、let、use等

文章目录 1. let2. with2.1 参数解析2.2 用法示例 3、use函数 1. let 2. with 2.1 参数解析 第一个参数可以是一个任意类型的对象&#xff0c; 第二个参数是一个Lambda表达式 with函数会在Lambda表达式中提供第一个参数对象的上下文&#xff0c; 并使用Lambda表达式中的最后…

2024山西省网络建设运维第十八届职业院校技能大赛解析答案(3. ansible 服务)

\3. ansible 服务 任务描述:请采用ansible,实现自动化运维。 (1)在Server2上安装系统自带的ansible-core,作为ansible 控制节 点。Linux1-linux7 作为 ansible 的受控节点。 (2)编写/root/resolv.yml 剧本,实现在所有linux主机的 /etc/resolv.conf文件,文件内容均…

PageOffice打开保存文件的执行流程(工作原理)

一、PageOffice打开文件 触发PageOffiice弹窗&#xff1a;在想要打开Office文件的页面上&#xff0c;通过点击按钮或链接来调用POBrowser.openWindow() 方法&#xff0c;此时会弹出一个PageOffice浏览器窗口&#xff0c;这个窗口中会自动加载openWindow()方法的第一个参数指向…

【FFmpeg系列】:音频处理

前言 在多媒体处理领域&#xff0c;FFmpeg无疑是一个不可或缺的利器。它功能强大且高度灵活&#xff0c;能够轻松应对各种音频和视频处理任务&#xff0c;无论是简单的格式转换&#xff0c;还是复杂的音频编辑&#xff0c;都不在话下。然而&#xff0c;要想真正发挥FFmpeg的潜…

段探测的研究

在介绍今天的内容之前&#xff0c;我们先要知道一些前置的知识 跳过繁琐的介绍&#xff0c;我们单刀直入&#xff0c;介绍一个划时代的CPU 8086 8086 从8086开始&#xff0c;CPU扩展到了16位&#xff0c;地址的位宽扩展到了20位&#xff0c;自此之后我们现在所熟知的计算机结…

pytorch环境问题以及探索Dataloader的数据格式

1 问题 DataLoader object is not subscriptable No module named matplotlib/torchvision.io 2 方法 针对问题一&#xff1a;“dataloader” object is not subscriptable 是一个 Python 中常见的错误。它通常是由于对 dataloader 取下标而导致的。 在 PyTorch 中&#xff0c;…

Linux:进程的优先级 进程切换

文章目录 前言一、进程优先级1.1 基本概念1.2 查看系统进程1.3 PRI和NI1.4 调整优先级1.4.1 top命令1.4.2 nice命令1.4.3 renice命令 二、进程切换2.1 补充概念2.2 进程的运行和切换步骤&#xff08;重要&#xff09; 二、Linux2.6内核进程O(1)调度队列&#xff08;重要&#x…