javascript 自定义元素弹窗跟随依附元素

这段代码实现了JavaScript点击事件监听,当点击某个元素时,会根据设定创建或查找相关容器,并显示在目标元素附近。同时,处理了元素的滚动事件,以保持跟随效果。代码还包含了阻止事件冒泡、元素定位和动态创建及移除元素的功能。
摘要由CSDN通过智能技术生成

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>

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值