【JS案例】JS实现手风琴效果

JS案例·手风琴

🌟效果展示

🌟HTML结构

🌟CSS样式

🌟实现思路 

🌟具体实现

1.绑定事件

 2.自定义元素属性

 3.切换菜单

🌟完整JS代码

🌟写在最后 


🌟效果展示


🌟HTML结构

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><link rel="stylesheet" href="./index.css" /></head><body><ul class="menu-container"><li class="menu"><h2>一级菜单1</h2><ul class="submenu"><li>二级菜单1</li><li>二级菜单2</li><li>二级菜单3</li><li>二级菜单4</li></ul></li><li class="menu"><h2>一级菜单2</h2><ul class="submenu"><li>二级菜单1</li><li>二级菜单2</li><li>二级菜单3</li><li>二级菜单4</li></ul></li><li class="menu"><h2>一级菜单3</h2><ul class="submenu"><li>二级菜单1</li><li>二级菜单2</li><li>二级菜单3</li><li>二级菜单4</li></ul></li><li class="menu"><h2>一级菜单4</h2><ul class="submenu"><li>二级菜单1</li><li>二级菜单2</li><li>二级菜单3</li><li>二级菜单4</li></ul></li></ul><script src="./animate.js"></script><script src="./index.js"></script></body>
</html>

dom结构只做参考,各种形式实现都可以,引入的animate.js文件是在前面文章中封装的方法,如下:

function createAnimation(options) {var from = options.from; // 起始值var to = options.to; // 结束值var totalMS = options.totalMS || 1000; // 变化总时间var duration = options.duration || 15; // 动画间隔时间var times = Math.floor(totalMS / duration); // 变化的次数var dis = (to - from) / times; // 每一次变化改变的值var curTimes = 0; // 当前变化的次数var timerId = setInterval(function () {from += dis;curTimes++; // 当前变化增加一次if (curTimes >= times) {// 变化的次数达到了from = to; // 变化完成了clearInterval(timerId); // 不再变化了options.onend && options.onend();}// 无数的可能性options.onmove && options.onmove(from);}, duration);
}

🌟CSS样式

h2 {margin: 0;padding: 0;font-size: 100%;font-weight: normal;
}
ul {margin: 0;padding: 0;list-style: none;
}.menu-container {width: 200px;margin: 0 auto;line-height: 30px;
}.menu-container h2 {padding: 0 25px;cursor: pointer;background: lightblue;
}.submenu {background: #e0f0f7;padding: 0 30px;/*height: 0;*//*overflow: hidden;*/
}
.menu {margin: 20px 0;
}.submenu li {height: 30px;
}

🌟实现思路 

在敲完上面HTML文件和CSS文件后可以看到下图效果:

而要实现一二级菜单的折叠效果,那我们应该要先把二级菜单隐藏,这里可以使用高度height来隐藏,给.submenu加上height:0;overflow:hidden;样式得到下图效果:

所以接下来我们要做的就是控制二级菜单高度变化。


🌟具体实现

1.绑定事件

获取所有一级菜单并绑定点击事件,并且使用nextElementSibling拿到兄弟节点。

let titles = document.querySelectorAll('.menu h2'); // 获取所有的一级标题元素
for (let i = 0; i < titles.length; i++) {titles[i].onclick = function () {console.log(this,this.nextElementSibling)};
}

 2.自定义元素属性

因为有多个一级菜单,并且当一个一级菜单展开时,其他的需要收起,那么怎么知道每个菜单当前状态呢,我这里是使用自定义元素属性来实现:

<ul class="submenu"></ul>设置status属性,定三个值:

1.opened // 表示二级菜单打开状态

2.playing // 表示正在打开或关闭状态

3.closed // 表示二级菜单关闭状态

两个相关方法:

setAttribute(name,value) 设置元素属性值

getAttribute(name) 获取元素属性值

 3.切换菜单

接下来定义toggleSubmenu(sumMenu),传入nextElementSibling获取的节点,根据状态来控制打开或关闭

function toggleSubmenu(subMenu) {let status = subMenu.getAttribute('status');if (status === 'playing') {// 正在播放动画return;} else if (status === 'opened') {// 关闭closeSubmenu(subMenu);} else {// 打开openSubmenu(subMenu);}
}

打开子菜单

// 打开子菜单
function openSubmenu(subMenu) {// 子菜单是有状态(关闭、打开、正在播放动画)// 通过自定义属性status,判定它的状态let status = subMenu.getAttribute('status');if (status !== 'closed' && status) {// 不是关闭状态return; // 啥也不干}subMenu.setAttribute('status', 'playing');// 将子菜单的高度从0变到?(子项数量*itemHeight)createAnimation({from: 0,to: itemHeight * subMenu.children.length,totalMS: totalMS,onmove: function (n) {subMenu.style.height = n + 'px';},onend: function () {subMenu.setAttribute('status', 'opened');},});
}

关闭子菜单

// 关闭子菜单
function closeSubmenu(subMenu) {// 子菜单是有状态(关闭、打开、正在播放动画)// 通过自定义属性status,判定它的状态let status = subMenu.getAttribute('status');if (status !== 'opened') {// 不是打开状态return; // 啥也不干}subMenu.setAttribute('status', 'playing');// 将子菜单的高度从0变到?(子项数量*itemHeight)createAnimation({from: itemHeight * subMenu.children.length,to: 0,totalMS: totalMS,onmove: function (n) {subMenu.style.height = n + 'px';},onend: function () {subMenu.setAttribute('status', 'closed');},});
}

通过对状态的判断打开关闭子菜单,函数中使用的动画方法为animate.js方法。


🌟完整JS代码

let titles = document.querySelectorAll('.menu h2'); // 获取所有的标题元素
var itemHeight = 30; // 每个子菜单的高度
var totalMS = 300; // 动画播放的总时长for (let i = 0; i < titles.length; i++) {titles[i].onclick = function () {// 收起其他所有菜单var beforeOpened = document.querySelector('.submenu[status=opened]');if (beforeOpened) {closeSubmenu(beforeOpened);}console.log(this,this.nextElementSibling)toggleSubmenu(this.nextElementSibling);};
}// 打开子菜单
function openSubmenu(subMenu) {// 子菜单是有状态(关闭、打开、正在播放动画)// 通过自定义属性status,判定它的状态let status = subMenu.getAttribute('status');if (status !== 'closed' && status) {// 不是关闭状态return; // 啥也不干}subMenu.setAttribute('status', 'playing');// 将子菜单的高度从0变到?(子项数量*itemHeight)createAnimation({from: 0,to: itemHeight * subMenu.children.length,totalMS: totalMS,onmove: function (n) {subMenu.style.height = n + 'px';},onend: function () {subMenu.setAttribute('status', 'opened');},});
}// 关闭子菜单
function closeSubmenu(subMenu) {// 子菜单是有状态(关闭、打开、正在播放动画)// 通过自定义属性status,判定它的状态let status = subMenu.getAttribute('status');if (status !== 'opened') {// 不是打开状态return; // 啥也不干}subMenu.setAttribute('status', 'playing');// 将子菜单的高度从0变到?(子项数量*itemHeight)createAnimation({from: itemHeight * subMenu.children.length,to: 0,totalMS: totalMS,onmove: function (n) {subMenu.style.height = n + 'px';},onend: function () {subMenu.setAttribute('status', 'closed');},});
}// 切换子菜单
function toggleSubmenu(subMenu) {let status = subMenu.getAttribute('status');if (status === 'playing') {// 正在播放动画return;} else if (status === 'opened') {// 关闭closeSubmenu(subMenu);} else {// 打开openSubmenu(subMenu);}
}

🌟写在最后 

本专栏将持续更新原生JS案例,提供一些工作中也能用上的一些小案例,详细讲解分析,提神JS开发水平与开发思路的积累,如果文中出现有瑕疵的地方各位通过评论或者私信联系我,我们一起进步,有兴趣的伙伴可以订阅一下:点击关注JS经典案例专栏

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

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

相关文章

Java课题笔记~ 综合案例

3.综合案例 3.1 功能介绍 以上是我们在综合案例要实现的功能。除了对数据的增删改查功能外&#xff0c;还有一些复杂的功能&#xff0c;如 批量删除、分页查询、条件查询 等功能 批量删除 功能&#xff1a;每条数据前都有复选框&#xff0c;当我选中多条数据并点击 批量删除 按…

PHP环境配置

1.服务器 简单理解&#xff1a;服务器也是一台计算机&#xff0c;只是比平时用到的计算机在性能上更强大&#xff0c;开发中通常都需要将开发好的项目部署到服务器进行访问&#xff0c;例如&#xff1a;我们可以访问百度、淘宝、京东等&#xff0c;都是因为有服务器的存在&…

【C++】—— 异常处理

前言&#xff1a; 本期&#xff0c;我将给大家讲解的是有关 异常处理 的相关知识&#xff01; 目录 &#xff08;一&#xff09;C语言传统的处理错误的方式 &#xff08;二&#xff09;C异常概念 &#xff08;三&#xff09;异常的使用 1、异常的抛出和捕获 1️⃣ 异常的…

vue使用命令npm install 报错 cb() never called!

一.错误说明,npm本身下载就慢&#xff0c;有可能是网络的问题。 二.解决方案,把npm设置成淘宝镜像后,再重新npm install npm config set registry https://registry.npm.taobao.org 三.还是不行&#xff0c;还会出现同样的问题&#xff0c;那接下来先清理一下npm缓存 npm cache…

工地扬尘监测系统 yolo

工地扬尘监测系统算法能够通过yolo网络框架模型&#xff0c;工地扬尘监测系统算法自动对区域的扬尘、粉尘颗粒进行实时监测识别&#xff0c;并及时进行预警&#xff0c;有效防止扬尘污染。Yolo意思是You Only Look Once&#xff0c;它并没有真正的去掉候选区域&#xff0c;而是…

Arduino程序设计(四)按键消抖+按键计数

按键消抖按键计数 前言一、按键消抖二、按键计数1、示例代码2、按键计数实验 参考资料 前言 本文主要介绍两种按键控制LED实验&#xff1a;第一种是采用软件消抖的方法检测按键按下的效果&#xff1b;第二种是根据按键按下次数&#xff0c;四个LED灯呈现不同的流水灯效果。 一…

异地使用PLSQL远程连接访问Oracle数据库【内网穿透】

文章目录 前言1. 数据库搭建2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射 3. 公网远程访问4. 配置固定TCP端口地址4.1 保留一个固定的公网TCP端口地址4.2 配置固定公网TCP端口地址4.3 测试使用固定TCP端口地址远程Oracle 前言 Oracle&#xff0c;是甲骨文公司的一款关系…

Hive Cli / HiveServer2 中使用 dayofweek 函数引发的BUG!

文章目录 前言dayofweek 函数官方说明BUG 重现Spark SQL 中的使用总结 前言 使用的集群环境为&#xff1a; hive 3.1.2spark 3.0.2 dayofweek 函数官方说明 dayofweek(date) - Returns the day of the week for date/timestamp (1 Sunday, 2 Monday, …, 7 Saturday). …

Win11共享文件,能发现主机但无法访问,提示找不到网络路径

加密长度选择如下&#xff1a; 参考以下链接&#xff1a; Redirectinghttps://answers.microsoft.com/zh-hans/windows/forum/all/win11%E8%AE%BE%E7%BD%AE%E6%96%87%E4%BB%B6%E5%A4%B9/554343a9-d963-449a-aa59-ce1e6f7c8982?tabAllReplies#tabs

【LeetCode-中等题】189. 轮转数组

题目 题解一&#xff1a;开辟数组 取模运算寻找位置(ik)mod n 新位置 思路&#xff1a;通过&#xff0c;开辟数组 取模运算寻找新位置------位置(ik)mod n 新位置 int[] newNums new int[nums.length];for(int i 0;i<nums.length;i){newNums[(ik)%nums.length] nums[i…

网络知识点之-堆叠与集群(2-集群)

本文章收录至《网络》专栏&#xff0c;点击右上角专栏图标可访问本专栏&#xff01; 集群是一种用于集团调度指挥通信的​​​​​​移动通信系统&#xff0c;主要应用在专业移动通信领域。该系统具有的可用信道可为系统的全体用户共用&#xff0c;具有自动选择信道功能&#x…

基于MATLAB开发AUTOSAR软件应用层Code mapping专题-part 4 Data store标签页介绍

这篇文章我们继续讲解code-mapping的Data stores页,这个页的内容对应的SIMULINK中的模块是Data store memory。 我们首先在模型中创建一个Data store memory模块,如图: Data store memory模块的作用相当于一个全局变量,我们可以在模型的功能逻辑里将一个信号存进去,在另…

[oneAPI] 基于BERT预训练模型的SWAG问答任务

[oneAPI] 基于BERT预训练模型的SWAG问答任务 基于Intel DevCloud for oneAPI下的Intel Optimization for PyTorch基于BERT预训练模型的SWAG问答任务数据集下载和描述数据集构建问答选择模型训练 结果参考资料 比赛&#xff1a;https://marketing.csdn.net/p/f3e44fbfe46c465f4d…

【Hadoop】HDFS读写流程和客户端命令使用

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,Java基础学习,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的…

一文速学-让神经网络不再神秘,一天速学神经网络基础-前向传播(三)

前言 思索了很久到底要不要出深度学习内容&#xff0c;毕竟在数学建模专栏里边的机器学习内容还有一大半算法没有更新&#xff0c;很多坑都没有填满&#xff0c;而且现在深度学习的文章和学习课程都十分的多&#xff0c;我考虑了很久决定还是得出神经网络系列文章&#xff0c;…

【Linux】深入理解文件缓冲区

文章目录 问题引入如何理解缓冲区缓冲区刷新策略问题解释模拟一个文件缓冲区 问题引入 首先看一段代码&#xff1a; #include <stdio.h> #include <string.h> int main() {const char *msg0"hello printf\n";const char *msg1"hello fwrite\n&quo…

Matlab(变量与文本读取)

目录 1.变量&#xff08;数据&#xff09;类型转换 1.1 字符 1.2 字符串 1.3 逻辑操作与赋值 2.Struct结构体数组 2.1函数的详细介绍&#xff1a; 2.1.1 cell2struct 2.1.1.1 垂直维度转换 2.1.1.2 水平维度转换 2.1.1.3 部分进行转换 2.1.2 rmfield 2.1.3 fieldnames(查…

HTTP 协议

目录 ​编辑一、HTTP 协议是什么 二、抓包工具的使用 三、HTTP 请求 1、认识 URL 2、认识方法 3、认识请求 “报头” HOST &#xff1a; Content-Length 和 Content-Type​编辑 User-Agent Referer Cookie 四、HTTP 响应 1、认识状态码 2、通过 form 表单构造 H…

最小化安装移动云大云操作系统--BCLinux-for-Euler-22.10-everything-x86_64-230316版

CentOS 结束技术支持&#xff0c;转为RHEL的前置stream版本后&#xff0c;国内开源Linux服务器OS生态转向了开源龙蜥和开源欧拉两大开源社区&#xff0c;对应衍生出了一系列商用Linux服务器系统。BCLinux-for-Euler-22.10是中国移动基于开源欧拉操作系统22.03社区版本深度定制的…

读书笔记-《ON JAVA 中文版》-摘要23[第二十章 泛型-2]

文章目录 第二十章 泛型5. 泛型擦除5.1 泛型擦除5.2 迁移兼容性5.3 擦除的问题5.4 边界处的动作 6. 补偿擦除7. 边界8. 通配符8.1 通配符8.2 逆变 9. 问题10. 动态类型安全11. 泛型异常 第二十章 泛型 普通的类和方法只能使用特定的类型&#xff1a;基本数据类型或类类型。如果…