Skip to content

Instantly share code, notes, and snippets.

@dobbbri
Created February 27, 2017 14:39
Show Gist options
  • Save dobbbri/e8408bc9567e9de8a2c46d6966ccf7fa to your computer and use it in GitHub Desktop.
Save dobbbri/e8408bc9567e9de8a2c46d6966ccf7fa to your computer and use it in GitHub Desktop.
`v-dropdown` directive for Vue.js 2
/*
* @usage
*
* <div v-dropdown="{autoClose: true}">
* <button dropdown-toggle>Dropdown</button>
* <div class="dropdown-menu">
* This is the dropdown menu.
* </div>
* </div>
*
* Options:
* - autoClose: Boolean
* Whether to close dropdown menu after being clicked.
* - click: 'toggle' (default) | 'open' | false
* If 'toggle', the menu will be toggled on click.
* If 'open', the menu will keep open on click.
* Otherwise ignored.
* - focus: 'open' | false (default)
* If 'open', keep open when focused.
* Otherwise ignored.
*/
import Vue from 'vue';
Vue.directive('dropdown', {
bind: function (el, binding) {
function doClose() {
if (!isOpen) return;
isOpen = false;
el.classList.remove('show');
document.removeEventListener('mousedown', onClose, false);
}
function onClose(e) {
if (e && el.contains(e.target)) return;
doClose();
}
function onOpen(_e) {
if (isOpen) return;
isOpen = true;
el.classList.add('show');
document.addEventListener('mousedown', onClose, false);
}
function onToggle(_e) {
isOpen ? onClose() : onOpen();
}
function onBlur(_e) {
setTimeout(() => {
const activeEl = document.activeElement;
if (activeEl !== document.body && !el.contains(activeEl)) {
doClose();
}
});
}
let isOpen = false;
const toggle = el.querySelector('[dropdown-toggle]');
const {value} = binding;
const {autoClose, click='toggle', focus=false} = value || {};
if (click === 'toggle') {
toggle.addEventListener('click', onToggle, false);
} else if (click === 'open') {
toggle.addEventListener('click', onOpen, false);
}
if (focus === 'open') {
toggle.addEventListener('focus', onOpen, false);
toggle.addEventListener('blur', onBlur, false);
}
autoClose && el.addEventListener('mouseup', doClose, false);
el.classList.add('dropdown');
},
});
.dropdown {
position: relative;
&-menu {
position: absolute;
top: 100%;
left: 0;
// - fixed width
// width: 200px;
// - auto width without line wrap
// white-space: nowrap;
}
&:not(.show) .dropdown-menu {
display: none;
}
}
[dropdown-toggle] {
cursor: pointer;
user-select: none;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment