js代码
var bindeFollower;
var translateX = 0;
var translateY = 0;
var vPlacement = 'top-start';
var body, followers, container, followerContentElm, followerId;
window.onload = function () {
followers = document.querySelectorAll('.e-follower');
body = document.getElementsByTagName("body")[0];
for (var fs in followers) {
if (typeof followers[fs] === 'object') {
followers[fs].addEventListener('click', function (e) {
stopProp(e); // 防止事件冒泡导致触发body上绑定的点击事件
followerId = this.getAttribute('follower-id');
if (followerId) {
container = document.querySelector('div[' + followerId + ']');
showContainer()
} else {
let number = Math.ceil(Math.random() * 10000 + 9999);
let timer = (new Date()).getTime();
followerId = 'v-bind-follower-id-' + (number + timer);
this.setAttribute('follower-id', followerId)
bindeFollower = this;
if (this.dataset.targetclass) {
followerContentElm = document.getElementsByClassName(this.dataset.targetclass)[0];
createElem()
}
}
});
}
}
body.addEventListener("click", hideContainer);
body.addEventListener('mousedown', function (e) {
if (e.button !== 0) {
hideContainer()
}
e.preventDefault();
});
var ElementsWithScrolls = (function() {
var getComputedStyle = document.body && document.body.currentStyle ? function(elem) {
return elem.currentStyle;
} : function(elem) {
return document.defaultView.getComputedStyle(elem, null);
};
function getActualCss(elem, style) {
return getComputedStyle(elem)[style];
}
function isXScrollable(elem) {
return elem.offsetWidth < elem.scrollWidth &&
autoOrScroll(getActualCss(elem, 'overflow-x'));
}
function isYScrollable(elem) {
return elem.offsetHeight < elem.scrollHeight &&
autoOrScroll(getActualCss(elem, 'overflow-y'));
}
function autoOrScroll(text) {
return text == 'scroll' || text == 'auto';
}
function hasScroller(elem) {
return isYScrollable(elem) || isXScrollable(elem);
}
return function ElemenetsWithScrolls() {
return [].filter.call(document.querySelectorAll('*'), hasScroller);
};
})();
[].filter.call(ElementsWithScrolls(),function (elem) {
elem.addEventListener('scroll', elmClientRect)
})
};
window.onresize = function () {
if (container) {
removeContainer(container)
}
};
function addClass(elm, ...cls) {
elm.classList.add(...cls);
}
function removeClass(elm, ...cls) {
elm.classList.remove(...cls);
}
function elmClientRect() {
if(!container || !bindeFollower) return;
let content = container.firstElementChild;
let _rect = bindeFollower.getBoundingClientRect();
let _l = {x: _rect.left || 0, y: _rect.top || 0};
let _frect = followerContentElm.getBoundingClientRect() || {};
let _fheight = _frect.height || container.clientHeight + container.offsetHeight; //可视内容高度为283像素
if (_rect.top < (_rect.height + _fheight)) {
_l.y = (_rect.bottom+5) + _fheight;
vPlacement = 'top-start'
} else {
_l.y = _rect.top;
vPlacement = 'bottom'
}
_l.x=_rect.left-(content.clientWidth/2-_rect.width/2);
content.style.transform = 'translateX(' + (_l.x || '-100') + 'px) translateY(' + (_l.y || '-100') + 'px) translateY(-100%)';
return _l
}
/**
* 阻止事件冒泡
*/
function stopProp(e) {
e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true;
}
function createElem() {
container = document.createElement('div');
var content = document.createElement('div');
addClass(container, 'v-binder-follower-container');
container.setAttribute(followerId, '');
container.style.display = 'block';
container.style.zIndex = 2000;
container.style.opacity = 0;
container.style.position = 'absolute';
container.style.left = 0;
container.style.right = 0;
container.style.top = 0;
container.style.height = 0;
container.style.pointerEvents = 'none';
container.appendChild(content);
if(!followerContentElm.innerHTML.trim()){
removeContainer();
}
addClass(content, 'v-binder-follower-content');
content.innerHTML = followerContentElm.innerHTML || '';
body.appendChild(container);
let _translate=elmClientRect();
// removeContainer();
content.style.background='rgb(72, 72, 78)';
content.setAttribute('v-placement', vPlacement);
container.style.opacity = 1;
}
function hideContainer() {
removeContainer()
}
function showContainer() {
if (!container) return;
let disp = container.style.display;
if (disp === 'block') {
hideContainer();
return;
}
container.style.display = 'block';
container.style.zIndex = 2000;
container.style.opacity = 1;
}
function removeContainer() {
if (!container) return;
container.remove()
}
html:
<div class="n-tag e-follower"targetClass="dropdown-menu">点击依附</div>
<div class='dropdown-menu'>
这里是需要被依附html
</div>