如何在按钮单击时切换元素并在外部单击时关闭?

时间:2019-07-23 04:19:39

标签: javascript html css shopify

我想在单击某个元素的关联按钮时切换其可见性。另外,我希望可见元素在单击外部任何地方时都关闭。可见元素内的任何链接也应该能够被点击。这是针对Shopify主题的,不确定是否有区别。

我也尝试过在元素上使用焦点事件侦听器,但是存在相同的问题。

JavaScript

const selectors = {
  mobileDownBtns: document.querySelectorAll('.mobile-nav__down-btn'),
  mainDownBtns: document.querySelectorAll('.main-nav-list__down-btn'),
  mainParent: document.querySelectorAll('.main-nav-parent-item'),
  spotifyBtn: document.querySelector('#spotifyBtn')
}

selectors.spotifyBtn.addEventListener('click', toggleElement);

selectors.mainDownBtns.forEach(function(btn) {
  btn.addEventListener('click', toggleElement);
});

function toggleElement(event) {
  const btn = event.currentTarget;
  const elem = btn.nextElementSibling;
  const container = btn.parentElement;

  if (elem.classList.contains('show')) {
    btn.setAttribute('aria-expanded', 'false');
    elem.classList.remove('show');
    container.classList.remove('isActive');
  } else {
    btn.setAttribute('aria-expanded', 'true');
    elem.classList.add('show');
    container.classList.add('isActive');
  }
}

window.addEventListener('mousedown', function(e) {
  const container = document.querySelector('.isActive');
  const btn = container.querySelector('button');
  const child = container.querySelector('.show');

  if (e.target != container && e.target.parentNode !== container) {
    container.classList.remove('isActive');
    btn.setAttribute('aria-expanded', 'false');
    child.classList.remove('show');
  }
});

HTML

<ul class="site-header__icon-list small--hide">
        <li class="site-header__icon-list--item">
          <button aria-label="Check out my spotify playlist" aria-expanded="false" id="spotifyBtn">
            {% include 'alt-icon-music' %}
          </button>

          <div class="site-header__spotify">
            {% include 'spotify' %}
          </div>
        </li>
      </ul>

      <nav role="navigation" class="site-header__main-nav--wrapper small--hide">
        <ul class="main-nav-list">
          {% for link in linklists[section.settings.menu].links %}
            {% if link.links != blank %}
              <li class="main-nav-list__item">
                <div class="main-nav-parent-item">  
                  <button class="main-nav-list__down-btn site-header__icon" aria-controls="navigation" aria-label="See sub navigation" aria-expanded="false">
                    <span>
                      {{ link.title }}
                    </span>

                    {% include 'alt-icon-chevron-down' %}
                  </button>

                  <div class="main-nav-list__dropdown">
                    <ul class="main-nav-list__child-list{% if link.links.size > 7 %} long{% endif %}">
                      {% for childlink in link.links %}
                        <li class="main-nav-list__item child-item">
                          <a href="{{ childlink.url }}">
                            {{ childlink.title }}
                          </a>
                        </li>
                      {% endfor %}
                    </ul>
                  </div>
                </div>
              </li>
            {% else %}
              <li class="main-nav-list__item">
                <a href="{{ link.url }}">
                  {{ link.title }}
                </a>
              </li>
            {% endif %}
          {% endfor %}
        </ul>
      </nav>

我的切换功能本身可以很好地工作,但是当我添加窗口事件侦听器时,切换功能不再能满足我的需要。第一次单击该按钮有效(显示元素),而窗口侦听器有效(隐藏可见元素),但是对按钮的任何其他单击都不起作用。同样,尽管窗口侦听器可以关闭可见元素,但它不允许在关闭可见元素之前对其进行单击。

控制台上也出现错误

  

“未捕获的TypeError:无法读取null的属性'querySelector'”

但是当我使用console.log时,正确的变量会记录到控制台。

我已经为这个问题研究了几天。我对javascript还是很陌生,而且我不太确定这是怎么回事。预先感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

document.getElementById('#spotifyBtn')

使用“ document.getElementById”代替“ document.querySelector”

答案 1 :(得分:0)

我创建了一个类似的场景。 div本身和其中的项目也是可点击的。 #include <climits> // : : // Start with a table initialized to all zeroes. char is_op[1 << CHAR_BIT] = {0}; // Build the table any way you please. This way using a string is handy. const char* ops = "+-*/"; for (const char* op = ops; *op; op++) is_op[*op] = 1; // Then tests require no searching while(is_op[temp->left->oper] || is_op[temp->right->oper]) { // do something } https://codepen.io/anon/pen/OKMNEy