处理下拉列表的焦点状态

时间:2017-07-25 19:53:52

标签: javascript focus

我目前正在使用纯JavaScript创建一个下拉组件。当用户单击下拉切换时,将显示内容增益焦点及其内容。当用户在其外部单击时,内容将失去焦点并被隐藏。

到目前为止,它的效果很好。但是,我遇到了两个问题。

第一个是当点击下拉列表中的一个元素时(例如:锚标记),下拉列表会失去焦点,它不应该是。

第二个问题是,在显示下拉内容时单击下拉切换时,由于下拉切换中注册的点击,下拉应该关闭而不是关闭然后重新打开。

HTML:

<div class="dropdown">
    <a href="#" class="dropdown-toggle">Dropdown toggle</a>
    <div class="dropdown-content" tabindex="0">
        <ul>
            <li>
                <a href="http://example.com">My profile</a>
            </li>
            <li>
                <a href="http://example.com">Log out</a>
            </li>
        </ul>
    </div>
</div>

CSS:

.dropdown {
    position: relative; 
}

.dropdown.is-open .dropdown-content {
    display: block; 
}

.dropdown-content {
    display: none;
    position: absolute;
    top: 100%;
    width: 100%;
    padding: 0.5rem 0;
    background: #fff;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); 
}

JS:

class Dropdown {

    constructor(element) {
        this.element = element;
        this.toggle = this.element.querySelector('.dropdown-toggle');
        this.content = this.element.querySelector('.dropdown-content');

        this.bindings();
    }

    bindings() {
        this.toggle.addEventListener('click', this.open.bind(this));
        this.content.addEventListener('keydown', this.handleKeyDown.bind(this));
        this.content.addEventListener('focusout', this.close.bind(this));
    }

    open(e) {
        e.preventDefault();
        this.element.classList.add('is-open');
        this.content.focus();
    }

    close(e) {
        this.element.classList.remove('is-open');
    }

    handleKeyDown(e) {
        if (e.keyCode === 27) {
            this.close(e);
        }
    }

} 

document.querySelectorAll('.dropdown').forEach(dropdown => new Dropdown(dropdown));

我一直试图了解如何在没有运气的情况下解决这些问题。关于如何解决这些问题的任何想法?

1 个答案:

答案 0 :(得分:0)

经过一些测试后,我找到了一个有效的解决方案。请尝试以下代码

        class Dropdown {

            constructor(element) {
                this.element = element;
                this.toggle = this.element.querySelector('.dropdown-toggle');
                this.content = this.element.querySelector('.dropdown-content');

                this.bindings();
            }

            bindings() {
                this.toggle.addEventListener('click', this.open.bind(this));
                this.content.addEventListener('keydown', this.handleKeyDown.bind(this));
                this.element.addEventListener('focusout', this.onFocusOut.bind(this),true);
            }
            onFocusOut(e) {
                if (!this.element.contains(e.relatedTarget)) {
                    this.close(e)
                }
            }

            open(e) {
                e.preventDefault();
                this.element.classList.toggle('is-open');
                this.content.focus();
            }

            close(e) {
                e.preventDefault();
                this.element.classList.remove('is-open');
            }

            handleKeyDown(e) {
                if (e.keyCode === 27) {
                    this.close(e);
                }
            }

        }