【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.mzph.cn/news/59502.shtml

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

相关文章

什么是线程安全和线程不安全?

线程安全(Thread Safety)和线程不安全(Thread Unsafety)是与并发编程相关的概念,特别是在多线程环境中使用共享资源时会涉及到这些概念。 线程安全: 当多个线程同时访问共享资源时,如果在没有额外的同步措施的情况下,这些线程仍然能够正确地执行并保持数据的一致性,那…

【跨语言通讯】

传统的跨语言通讯方案&#xff1a; 基于SOAP消息格式的WebService 基于JSON消息格式的RESTful 服务 主要弊端&#xff1a; XML体积太大&#xff0c;解析性能极差 JSON体积相对较小&#xff0c;解析相对较快&#xff0c;但表达能力较弱 如今比较流行的跨语言通讯方案&…

【⑬MySQL | 数据类型(一)】简介 | 整数 | 浮点 | 定点 | 时间/日期类型

前言 ✨欢迎来到小K的MySQL专栏&#xff0c;本节将为大家带来MySQL数据类型简介 | 整数 | 浮点 | 定点 | 时间/日期类型的分享✨ 目录 前言0.数据类型简介1 整数类型2 浮点类型3 定点类型4 日期/时间类型总结 0.数据类型简介 数据类型&#xff08;data_type&#xff09;是指系…

安卓全局活动切换动画,windowAnimationStyle与overridePendingTransition两种实现

关于android:windowAnimationStyle 安卓全局活动切换动画&#xff0c;windowAnimationStyle与overridePendingTransition两种实现 Android动画全篇系列&#xff08;十一&#xff09;——Activity转场动画 Android Activity跳转动画 - overridePendingTransition用法及原理分…

链表(详解)

一、链表 1.1、什么是链表 1、链表是物理存储单元上非连续的、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表的指针地址实现&#xff0c;有一系列结点&#xff08;地址&#xff09;组成&#xff0c;结点可动态的生成。 2、结点包括两个部分&#xff1a;&#x…

经典问题解析四

关于动态内存分配 new 和 malloc 的区别是什么&#xff1f; delete 和 free 的区别是什么&#xff1f; new 关键字与 malloc 函数的区别 new 关键字是 C 的一部分 malloc 是由 C 库函数提供的函数 new 是以具体类型为单位进行内存分配 malloc 以字节为单位进行内存分配 …

【1267. 统计参与通信的服务器】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 这里有一幅服务器分布图&#xff0c;服务器的位置标识在 m * n 的整数矩阵网格 grid 中&#xff0c;1 表示单元格上有服务器&#xff0c;0 表示没有。 如果两台服务器位于同一行或者同一列&#xff…

OpenCV最常用的50个函数

Python版&#xff1a;OpenCV提供了众多图像处理算子和函数&#xff0c;涵盖了各种任务和技术。以下是OpenCV中一些常用的50个算子和函数&#xff1a; cv2.imread&#xff1a;用于读取图像文件。cv2.imshow&#xff1a;用于显示图像。cv2.imwrite&#xff1a;用于保存图像。cv2…

【Terraform学习】使用 Terraform 从 EC2 实例访问 S3 存储桶(Terraform-AWS最佳实战学习)

使用 Terraform 从 EC2 实例访问 S3 存储桶 实验步骤 前提条件 安装 Terraform&#xff1a; 地址 下载仓库代码模版 本实验代码位于 task_ec2_s3connet 文件夹中。 变量文件 variables.tf 在上面的代码中&#xff0c;您将声明&#xff0c;aws_access_key&#xff0c;aws_…

百亿数据查询秒级响应,观测体系之日志中心该如何玩转?

日志是处理生产故障、性能优化、业务分析的重要参考依据&#xff0c;是系统稳定运行不可或缺的一部分。随着业务系统规模急剧膨胀增大&#xff0c;尤其是是微服务架构逐渐普及&#xff0c;一个系统可能涉及多个应用模块与服务实例&#xff0c;传统模式下运维人员去定位问题显得…

一文速学-让神经网络不再神秘,一天速学神经网络基础-输出层(四)

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

反射的笔记

一.概念 运行过程中,对任意一个类都能获取类中的属性和方法,对任意一个对象都能调用对象中的属性和方法,动态获取信息及调用对象的方法,实现功能的反射机制 作用:动态获取类的信息 相关类主要包括:Class 类型; Constructor 构造方法; Method 方法; Field 属性,Class外的其他…

HTML5-1-标签及属性

文章目录 语法规范标签规范标签列表通用属性基本布局 页面的组成&#xff1a; HTML&#xff08;HyperText Markup Language&#xff0c;超文本标记语言&#xff09;是用来描述网页的一种语言&#xff0c;它不是一种编程语言&#xff0c;而是一种标记语言。 HTML5 是下一代 HTM…

vue3+antdesign table实现表格行颜色

实现效果&#xff1a; 代码&#xff1a; html: <a-table:columns"stockColumns":data-source"stockData"class"ant-table-striped":rowClassName"rowClassName"></table> js: const rowClassName computed(() > {re…

Windows下MATLAB调用Python函数操作说明

MATLAB与Python版本的兼容 具体可参看MATLAB与Python版本的兼容 操作说明 操作说明请参看下面两个链接&#xff1a; 操作指南 简单说明&#xff1a; 我安装的是MATLAB2022a和Python3.8.6&#xff08;安装时请勾选所有可以勾选的&#xff0c;包括路径&#xff09;。对应版本安…

归一化的作用,sklearn 安装

目录 归一化的作用&#xff1a; 应用场景说明 sklearn 准备工作 sklearn 安装 sklearn 上手 线性回归实战 归一化的作用&#xff1a; 归一化后加快了梯度下降求最优解的速度; 归一化有可能提高精度(如KNN) 应用场景说明 1&#xff09;概率模型不需要归一化&#xff…

ArrayList与顺序表

文章目录 一. 顺序表是什么二. ArrayList是什么三. ArrayList的构造方法四. ArrayList的常见方法4.1 add()4.2 size()4.3 remove()4.4 get()4.5 set()4.6 contains()4.7 lastIndexOf()和 indexOf(&#xff09;4.8 subList()4.9 clear() 以上就是ArrayList的常见方法&#xff01…

未检查的转换: ‘java.lang.Object‘ 转换为 ‘java.util.List

fastjson方式 Object object ... // 获取待转换的objectList<WbsCategory> list JSON.parseObject(JSON.toJSONString(object), new TypeReference<List<WbsCategory>>() {}); 在这个示例中&#xff0c;我们使用JSON.toJSONString()将object对象转换…

RHCE——九、SELinux

SELinux 一、概念1、作用2、SELinux与传统的权限区别 二、SELinux工作原理1、名词解释主体&#xff08;Subject&#xff09;目标&#xff08;Object&#xff09;策略&#xff08;Policy&#xff09;安全上下文&#xff08;Security Context&#xff09; 2、文件安全上下文查看1…

element——switch接口成功后赋值打开开关

应用场景 基本用法使用v-model双向绑定值&#xff0c;进行开关控制 例子1:需求&#xff1a; **点击switch&#xff0c;出弹窗&#xff0c;点击弹窗保存按钮调接口成功后再赋值&#xff08;row.orderButtonValue“1”&#xff09;打开switch开的状态变颜色。 在vue 中使用 :va…