如何实现点击页面任意位置关闭下拉菜单?
实现点击页面任意位置关闭语言切换下拉菜单
现有基于jQuery的语言切换下拉菜单,仅点击下拉选项时能关闭菜单,需求是点击页面任意位置都可关闭该菜单。
实现步骤
- 封装关闭逻辑:将关闭菜单的代码抽成独立函数,避免重复编写
- 阻止菜单区域事件冒泡:点击下拉菜单自身时,阻止事件传递到document,防止菜单刚打开就关闭
- 绑定document点击事件:判断点击目标是否属于下拉菜单区域,若不属于则触发关闭逻辑
修改后的完整代码
JavaScript 部分
let el = $('.switch'); let cur = el.find('.current'); let options = el.find('.options li'); let content = $('#content'); // 封装关闭下拉菜单的函数 function closeDropdown() { if (!el.hasClass('show-options')) return; el.removeClass('anim-options'); el.removeClass('show-shadow'); setTimeout(function() { el.removeClass('show-options'); }, 600); } // 切换下拉菜单显示/隐藏状态 el.on('click', function(e) { // 阻止事件冒泡,避免触发document的点击事件 e.stopPropagation(); if (el.hasClass('show-options')) { closeDropdown(); } else { el.addClass('show-options'); setTimeout(function() { el.addClass('anim-options'); }, 50); setTimeout(function() { el.addClass('show-shadow'); }, 200); } }); // 点击选项切换语言并关闭菜单 options.on('click', function(e) { e.stopPropagation(); let newLang = $(this).data('lang'); cur.find('span').text(newLang); content.attr('class', newLang); setLang(newLang); options.removeClass('selected'); $(this).addClass('selected'); closeDropdown(); }); // 点击页面其他区域关闭下拉菜单 $(document).on('click', function(e) { if (!$(e.target).closest('.switch').length) { closeDropdown(); } }); // 从本地存储读取当前语言 function getLang() { let lang; if (localStorage.getItem('currentLang') === null) { lang = cur.find('span').text(); } else { lang = JSON.parse(localStorage.getItem('currentLang')).toLowerCase(); } cur.find('span').text(lang); options.parent().find(`li[data-lang="${lang}"]`).addClass('selected'); content.attr('class', lang); } getLang(); // 将选中语言保存到本地存储 function setLang(newLang) { localStorage.setItem('currentLang', JSON.stringify(newLang).toLowerCase()); content.attr('class', newLang); }
CSS 部分
@import url("https://fonts.googleapis.com/css?family=Playfair+Display:400,900|Noto+Sans:400,400i,700&subset=latin-ext"); :root { font-size: 100%; --base-font-size: calc(15px + .5vw); --ratio: 1.18; --h6: calc(var(--base-font-size) * var(--ratio)); --h5: calc(var(--h6) * var(--ratio)); --h4: calc(var(--h5) * var(--ratio)); --h3: calc(var(--h4) * var(--ratio)); --h2: calc(var(--h3) * var(--ratio)); --h1: calc(var(--h2) * var(--ratio)); } body { font-family: "Noto Sans", Arial, sans-serif; font-size: 1.2rem; font-size: var(--base-font-size); line-height: 1.6; color: #313436; } #content { max-width: 48rem; margin: 0 auto; text-align: left; padding: 1rem 2rem; } #content:not(.en) [data-lang=en], #content:not(.sv) [data-lang=sv]{ display: none; } #content.en [data-lang=en],#content.sv [data-lang=sv]{ display: block; } h1 { font-family: "Playfair Display", "Noto Sans", Arial, sans-serif; font-weight: 900; font-size: var(--h1); line-height: calc(var(--h1) * 1.2); } h2 { font-size: var(--h2); line-height: calc(var(--h2) * 1.2); } h3 { font-size: var(--h3); line-height: calc(var(--h3) * 1.3); } h4 { font-size: var(--h4); line-height: calc(var(--h4) * 1.3); } h5 { font-size: var(--h5); line-height: calc(var(--h5) * 1.4); } h6 { font-size: var(--h6); line-height: calc(var(--h6) * 1.5); } .main-header { background-color: #3498DB; color: #FFFFFF; height: 56px; display: flex; padding: 0 2rem; box-shadow: 0 2px 12px -4px rgba(0, 0, 0, 0.4); } .main-header h1 { font-size: 1.25rem; line-height: 1.35; font-family: "Noto Sans", Arial, sans-serif; } .main-header .switch { margin-left: auto; } .switch { position: relative; cursor: pointer; display: flex; align-items: center; } .current { text-transform: uppercase; height: 42px; position: relative; z-index: 1; font-size: 1rem; text-align: center; line-height: 42px; display: flex; background-color: rgba(0, 0, 0, 0); transition: all 0.2s ease-out; border-radius: 3px; padding: 0 0.2em 0 0.7em; } .current span { display: inline-block; line-height: 1; padding: 0.7em 0.2em 0 0; } .current .arrow { display: inline-block; width: 20px; height: 20px; } .current:hover { background-color: rgba(0, 0, 0, 0.1); } .options { position: absolute; right: 0; top: 0.6em; z-index: 0; opacity: 0; transition: all 0.36s ease-out; display: none; overflow: hidden; box-shadow: 0 0 0 0 rgba(0, 0, 0, 0); } .switch.show-options .options { display: block; z-index: 5; } .switch.anim-options .options { opacity: 1; } .switch.show-shadow .options { box-shadow: 0 2px 12px -4px rgba(0, 0, 0, 0.4); } .options-list { color: #313436; margin: 0; padding: 0.4rem 0.8em; position: relative; z-index: 5; } .options-list li { list-style: none; padding: 0; margin: 0; padding: 0.75em; border-bottom: 1px solid #E1E4E6; transform: translateX(10px); transition: all 0.24s ease-out; transition-delay: 0.1s; opacity: 0; font-size: 1rem; line-height: 1.3; white-space: nowrap; } .options-list li:last-child { border-bottom: none; } .options-list li:nth-child(1) { transition-delay: 0.1s; } .options-list li:nth-child(2) { transition-delay: 0.15s; } .options-list li:nth-child(3) { transition-delay: 0.2s; } .options-list li:nth-child(4) { transition-delay: 0.25s; } .options-list li:nth-child(5) { transition-delay: 0.3s; } .options-list li.selected { color: #3498DB; } .switch.anim-options .options-list li { transform: translateX(0); opacity: 1; } #trans-circle { width: 80px; height: 80px; position: absolute; top: -80px; right: -80px; padding: 0; margin: 0; border: none; z-index: 1; transition: all 0.4s ease-out; transform: scale(0.5); overflow: hidden; } #trans-circle svg { max-width: 100%; max-height: 100%; } .switch.anim-options #trans-circle { transform: scale(9); }
HTML 部分
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css"> <header class="main-header"> <h1 data-lang="en">Language Switch</h1> <h1 data-lang="sv">Språkbyte</h1> <div class="switch"> <div class="current"> <span>en</span> <em class="arrow"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18"><title>ic_arrow_drop_down_18px</title> <g fill="#FFFFFF"> <path d="M5 8l4 4 4-4z"></path> </g> </svg></em> </div> <div class="options"> <ul class="options-list"> <li data-lang="en">English</li> <li data-lang="sv">Svenska</li> </ul> <div id="trans-circle"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120"> <g id="circle" fill="none" fill-rule="evenodd"> <circle id="bg" cx="60" cy="60" r="60" fill="#FFFFFF"/> </g> </svg> </div> </div> </div> </header> <main id="content" class="en"> <h1 data-lang="en">Design</h1> <h1 data-lang="sv">konstruktion</h1> </main>
内容的提问来源于stack exchange,提问作者dede1907
相关产品推荐
相关产品推荐

