简体   繁体   English

我编码了一个纯JavaScript下拉脚本,它有一些(切换)问题

[英]I encoded a pure javascript dropdown script, it has some (toggle) problems

I encoded a pure javascript dropdown script, it has some (toggle) problems. 我编码了一个纯JavaScript下拉脚本,它有一些(切换)问题。

Now, when i click button dropdown opens with class tags ( .is-open .in ) . 现在,当我单击按钮时,将打开带有类标签( .is-open .in )下拉列表。

After i am click trigger button again: it give wrong work. 在我再次单击触发按钮后:它提供了错误的工作。 But i am click body or press ESC key,it closes properly.. 但是我单击正文或按ESC键,它可以正常关闭。

The problem there, script remove ".is-open.in" tags, after again added... of course it's ridiculous after that. 那里的问题是,脚本删除了“ .is-open.in”标记,然后再次添加了……当然,这之后很荒谬。

Because for eventListener, program again run open(e) . 因为对于eventListener,程序再次运行open(e)

 const ClassName = { OPEN: 'is-open', IN: 'in', OUT: 'out', MENU: 'dropdown-menu', } const KeyCodes = { ESC: 27 } const DefaultConfig = { transition: true, } const throwError = message => window.console.error(`bozDropdown: ${message}`); const reflow = element => element.offsetHeight; class bozDropdown { constructor(id, config) { this.id = id; this.config = Object.assign({}, DefaultConfig, config); this.dropdown = bozDropdown.findDropdown(this.id); this.menu = this.dropdown.querySelector(`.${ClassName.MENU}`); this.isOpen = false; this.isInit = false; this.triggers = bozDropdown.findTriggers(this.id); this.closeEls = null; this.open = this.open.bind(this); this.close = this.close.bind(this); this.onDismiss = this.onDismiss.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); } init() { if (this.isInit) { throwError('Event listeners already added.'); return; } this.triggers.forEach(trigger => trigger.addEventListener('click', this.open)); this.isInit = true; } destroy() { if (!this.isInit) { throwError('Event listeners already removed.'); return; } this.triggers.forEach(trigger => trigger.removeEventListener('click', this.open)); this.isInit = false; } open(e) { if (this.isOpen) { return; } if (e) e.preventDefault(); if (typeof this.config.beforeOpen === 'function') { this.config.beforeOpen(); } this.menu.style.display = 'block'; if (this.config.transition) { this.dropdown.classList.add(ClassName.OPEN); this.dropdown.classList.add(ClassName.IN); this.menu.classList.add(ClassName.OPEN); this.menu.classList.add(ClassName.IN); this.openWithTransition(); } else { this.dropdown.classList.add(ClassName.OPEN); this.menu.classList.add(ClassName.OPEN); } document.addEventListener('mousedown', this.onDismiss); document.addEventListener('keydown', this.handleKeyDown); this.closeEls = [...this.dropdown.querySelectorAll('[data-dismiss="dropdown"]')]; this.closeEls.forEach(button => button.addEventListener('click', this.close)); this.isOpen = true; if (typeof this.config.onOpen === 'function' && !this.config.transition) { this.config.onOpen(); } } openWithTransition() { const openTransitionHandler = () => { this.menu.removeEventListener('animationend', openTransitionHandler); if (typeof this.config.onOpen === 'function') { this.config.onOpen(); } }; this.menu.addEventListener('animationend', openTransitionHandler); } close() { if (typeof this.config.beforeClose === 'function') { this.config.beforeClose(); } if (this.config.transition) { this.dropdown.classList.remove(ClassName.IN); this.dropdown.classList.remove(ClassName.OPEN); this.dropdown.classList.add(ClassName.OUT); this.menu.classList.remove(ClassName.IN); this.menu.classList.remove(ClassName.OPEN); this.menu.classList.add(ClassName.OUT); this.closeWithTransition(); } else { this.menu.style.display = 'none'; this.menu.classList.remove(ClassName.OPEN); this.dropdown.classList.remove(ClassName.OPEN); if (typeof this.config.onClose === 'function') { this.config.onClose(); } } document.removeEventListener('mousedown', this.onDismiss); document.removeEventListener('keydown', this.handleKeyDown); this.closeEls.forEach(button => button.removeEventListener('click', this.close)); this.isOpen = false; } closeWithTransition() { const closeTransitionHandler = () => { this.menu.removeEventListener('animationend', closeTransitionHandler); this.menu.style.display = 'none'; this.menu.classList.remove(ClassName.OUT); this.dropdown.classList.remove(ClassName.OUT); if (typeof this.config.onClose === 'function') { this.config.onClose(); } }; this.menu.addEventListener('animationend', closeTransitionHandler); } onDismiss(e) { if (!this.menu.contains(e.target) && this.isOpen) { this.close(); } } handleKeyDown(e) { switch (e.keyCode) { case KeyCodes.ESC: this.close(); break; default: break; } }; static findTriggers(id) { return [...document.querySelectorAll(`[data-toggle="dropdown"][data-target="${id}"]`)]; } static findDropdown(id) { return document.getElementById(id); } } if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { module.exports = bozDropdown; } else { window.bozDropdown = bozDropdown; } const dropdown1 = new bozDropdown('dropdown1', { onOpen: function() { console.log("Açıldı 1") }, beforeOpen: function() { console.log("Açılacak 1") } }); dropdown1.init(); 
 :root { --duration: 350ms; } .dropdown { position: relative; } .dropdown-menu { position: absolute; top: 100%; left: 0; z-index: 1000; display: none; float: left; min-width: 10rem; padding: .5rem 0; margin: .125rem 0 0; font-size: 1rem; color: #212529; text-align: left; list-style: none; background-color: #fff; background-clip: padding-box; border: 1px solid rgba(0, 0, 0, .15); border-radius: .25rem; } .dropdown.in .dropdown-menu { animation: scaleUp var(--duration) ease-in-out; } .dropdown.out .dropdown-menu { animation: scaleDown var(--duration) ease-in-out; } @keyframes scaleUp { 0% { transform: scale(1.2); opacity: 0; } 100% { transform: scale(1); opacity: 1; } } @keyframes scaleDown { 0% { transform: scale(1); opacity: 1; } 100% { transform: scale(1.2); opacity: 0; } } 
 <div class="dropdown" id="dropdown1"> <button data-toggle="dropdown" data-target="dropdown1">Basic Dropdown 1</button> <div class="dropdown-menu"> <ul> <li>Onur</li> <li>Onur</li> <li>Onur</li> <li>Onur</li> </ul> </div> </div> 

For resolve this problem i am try this code: if(this.isOpen) { return; } 为解决此问题,我尝试使用以下代码: if(this.isOpen) { return; } if(this.isOpen) { return; } Line: 71 But it do not solve my problem! if(this.isOpen) { return; } 行:71但这不能解决我的问题!

Your closeTransitionHandler function is not being triggered when you click on the button element and the dropdown is already visible as the animation does not have time to end as the menu appears again when calling open() (It starts fading, but its opened again before the close animation ends, so it never really ends). 当您单击按钮元素时,不会触发closeTransitionHandler函数,并且下拉菜单已经可见,因为动画没有时间结束,因为调用open()时菜单再次出现(它开始褪色,但是在结束动画,所以它永远不会真正结束)。 This causes the out classes are never removed from the element. 这将导致out类永远不会从元素中删除。

A simple fix that I have tried is to set the this.isOpen = false; 我尝试过的一个简单修复方法是设置this.isOpen = false;。 at the end of closeTransitionHandler function and inside the else of this.config.transition of close() function. 在closeTransitionHandler函数的末尾和close()函数的this.config.transition的else内部。 Code snippet below 下面的代码段

  close() {
    if (typeof this.config.beforeClose === 'function') {

      this.config.beforeClose();

    }

    if (this.config.transition) {
      this.dropdown.classList.remove(ClassName.IN);
      this.dropdown.classList.remove(ClassName.OPEN);
      this.dropdown.classList.add(ClassName.OUT);
      this.menu.classList.remove(ClassName.IN);
      this.menu.classList.remove(ClassName.OPEN);
      this.menu.classList.add(ClassName.OUT);
      this.closeWithTransition();
    } else {
      this.menu.style.display = 'none';
      this.menu.classList.remove(ClassName.OPEN);
      this.dropdown.classList.remove(ClassName.OPEN);

      if (typeof this.config.onClose === 'function') {
        this.config.onClose();
      }
      this.isOpen = false;
    }

    document.removeEventListener('mousedown', this.onDismiss);
    document.removeEventListener('keydown', this.handleKeyDown);

    this.closeEls.forEach(button => button.removeEventListener('click', this.close));

  }

  closeWithTransition() {

    const closeTransitionHandler = () => {

      this.menu.removeEventListener('animationend', closeTransitionHandler);
      this.menu.style.display = 'none';
      this.menu.classList.remove(ClassName.OUT);
      this.dropdown.classList.remove(ClassName.OUT);

      if (typeof this.config.onClose === 'function') {
        this.config.onClose();
      }
      this.isOpen = false;
    };

    this.menu.addEventListener('animationend', closeTransitionHandler);
  }

Hope it helps! 希望能帮助到你!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM