8

是否可以编写一个 JavaScript 函数,给定任何 HTML 元素(在屏幕上可见),它会创建另一个 HTML 元素堆叠在它上面(以便覆盖它)?然后,如果我调整页面大小,它会完全按照它所覆盖的组件移动。

(例如,如果我使用 getBoundingClientRect 如果原始组件的宽度以百分比表示,它将不起作用)

该函数应该处理元素(在输入中)是否具有边距、填充、边框、其显示是块还是内联等的任何情况。

我尝试添加一个位置:相对于父组件,然后在“封面”组件上创建一个位置:绝对。这不起作用,因为它不处理填充或边距等情况。

注意:没有 jQuery。如果可能的话,纯“跨浏览器”JavaScript

4

11 回答 11

2

使用jQuery写在下面的封面函数请试试这是否适合你

嗨,我已经更新了满足您需求的代码...

function coverDiv(sourceId, targetId){  
    var source = document.getElementById(sourceId);
    var sourceComputed = window.getComputedStyle(source);
    var target = document.getElementById(targetId); 
    var positioningProps = ["float","width","height","left","top","marginLeft","marginTop","paddingLeft","paddingTop"];
    var cssText = "";
    for(var i in positioningProps){        
            cProp = positioningProps[i];              
            if(source.style[cProp] == "" || source.style[cProp] == null)
                target.style[cProp] =  sourceComputed[cProp];
            else
                target.style[cProp] = source.style[cProp];
    }
    source.style['position'] = "absolute";
    source.style['zIndex'] = "1";
    target.style['position'] = "absolute";
    target.style['zIndex'] = "999";
}

在这里尝试演示:: http://jsfiddle.net/tushhtrivedi/RDFRm/10/

于 2013-04-09T06:52:03.053 回答
2

我建议您将一个元素附加到您希望“覆盖”的元素,给父元素位置:相对,并给附加元素位置:绝对;顶部:0;左:0;底部:0;右:0;

例子...

标记:

...
<div id="content">
    <div class="cover"></div>
    <div></div>
</div>
...

CSS:

.cover { position: relative; }
.cover .mask { position: absolute; top:0; left:0; bottom: 0; right: 0; }

jQuery

$(function(){
    $('.cover').append('<div class="mask" />');
});

此方法将允许您忽略任何调整大小时发生的情况......

==========================

根据反馈改进...

填充应该按绝对位置排序,对于边框和边距,您需要使用一些 js 并在掩码元素上设置负边距。我包含的演示链接仅处理具有统一填充/边距的元素 - 如果您在每一侧都有具有不同填充/边距的元素,那么您将不得不做更多的解析。

附加的 javascript 看起来像:

var $hideme = $('.cover');
$('.mask',$hideme).css("margin", "-="+$hideme.css('border-width'));
$('.mask',$hideme).css("margin", "-="+$hideme.css('margin'));

演示

于 2013-04-05T15:51:14.850 回答
1
function addCover(id) {
 var element = document.getElementById(id);

 var wrapper = document.createElement('div');
 var cover = document.createElement('div');

 wrapper.setAttribute('style', 'position: relative;');

 cover.setAttribute('style','position:absolute; top: 0; bottom:0; right: 0; left: 0; width: 100%; height: 100%; z-index:10;')

 element.parentElement.replaceChild(wrapper, element);

 wrapper.appendChild(element);
 wrapper.appendChild(cover);    

}
于 2013-04-08T11:14:42.143 回答
1

添加 position:relative to parent 组件和 position:absolute 在封面上听起来是可行的,实际上,只要你考虑到 padding、margin 和border。将顶部设置为 -1*(padding-top+margin-top+border-width-top),其他边以此类推。在不设置宽度或高度的情况下执行此操作,它会自行调整大小以将其边缘贴在您放置它们的位置。但是,这将无法在不能包含 div 的组件上工作。

详细说明:

您使用这种方法遇到的问题是,如果您尝试使用 width:100px; 覆盖一个元素;填充:10px;边框:1px 纯黑色,封面只有 100 像素宽,不覆盖 10 像素的填充或 1 像素的边框。您可以通过将 left 和 right 设置为 -11px 而不是 0 来补偿这一点。您必须在添加封面的 javascript 函数中对此进行补偿,除非您有兴趣覆盖的所有内容都具有相同的填充、边框和边距.

于 2013-04-05T15:50:43.717 回答
1

那么,一个元素应该完全隐藏另一个元素吗?直到什么?一个给定的时间,它被隐藏以显示它下面的元素?

为什么不直接用新元素替换元素,直到您希望原始元素可见?这将解决滚动问题。

使用纯 JavaScript 更容易做到。

除非您要替换框架站点上的元素,否则您首先不应该这样做,恕我直言。

于 2013-04-09T11:21:13.660 回答
0

我希望这是你想要的

//https://stackoverflow.com/a/442474/1989562
function getOffset(el) {
var _x = 0;
var _y = 0;
while (el && !isNaN(el.offsetLeft) && !isNaN(el.offsetTop)) {
    _x += el.offsetLeft - el.scrollLeft;
    _y += el.offsetTop - el.scrollTop;
    el = el.offsetParent;
}
return {
    top: _y,
    left: _x
};
}

function overlap(element) {
this.element = element;
this.overlapper = document.createElement("Div");
this.__constructor = function () {
    var left = getOffset(this.element).left;
    var top = getOffset(this.element).top;
    var width = this.element.offsetWidth;
    var height = this.element.offsetHeight;
    this.overlapper.style.position = "absolute";
    this.overlapper.style.width = width + "px";
    this.overlapper.style.height = height + "px";
    this.overlapper.style.left = left + "px";
    this.overlapper.style.top = top + "px";
    this.overlapper.style.background = "black";
    this.overlapper.style.zIndex = 999;
    document.body.appendChild(this.overlapper);
}
this.update = function () {
    var left = getOffset(this.element).left;
    var top = getOffset(this.element).top;
    var width = this.element.offsetWidth;
    var height = this.element.offsetHeight;
    this.overlapper.style.top = top + "px";
    this.overlapper.style.left = left + "px";
    this.overlapper.style.width = width + "px";
    this.overlapper.style.height = height + "px";
}
this.__constructor();
}

元素函数的偏移量在这篇文章 https://stackoverflow.com/a/442474/1989562

我以小提琴为例

http://jsfiddle.net/takedownbig/ASuEJ/

它将获取元素在屏幕上的实际位置,要使元素更新必须触发对象的更新功能,我建议像我的示例一样使用。在 ie9+ 上工作我也想在 ie8 上工作:/

@edit:该函数没有所有的更新方式,但如果你找到它们,你可以简单地触发更新函数来修复实际的位置和宽度。

于 2013-04-11T10:07:35.800 回答
0

假设我对您的理解正确,那么简单(也是最好)的方法是在您要覆盖的元素内嵌套一个元素。外部元素应具有相对位置,嵌套元素应具有绝对定位(每边设置为 0)。为每个元素使用 z-index,您可以将它们叠加在一起,而不管填充或边距。

<style>
.layer-1 {
    width: 100px;
    height: 100px;
    background: red;
    position: relative;
    z-index: 1;
}
.layer-2 {
    background: blue;
    position: absolute;
    z-index:2;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
}
</style>
<div class="layer-1">
    <span class="layer-2"></span>
</div>

只有几行代码的实时示例,仅 CSS/HTML:http: //jsfiddle.net/3hBsZ/

编辑:重新阅读了这个问题,我确实误读了它。您正在寻找一种 javascript 解决方案,而不是基于 CSS 的解决方案。但是,这种 CSS 解决方案将比基于 javascript 的解决方案更有效且跨浏览器。只是我的观点...

于 2013-04-09T17:20:54.770 回答
0

这是一个甚至适用于固定或绝对定位元素的版本,并且在滚动或重排更改元素的位置或大小时不会中断:

function cover(el, filling) {
  var c = document.createElement('div');
  c.style.background = filling;
  var els = window.getComputedStyle(el)
  c.style.position = els.position=='fixed' ? 'fixed':'absolute';
  c.style.zIndex = parseInt(els.zIndex)+1;
  document.body.appendChild(c);
  var place = function() {   
    c.style.width = el.offsetWidth+'px';
    c.style.height = el.offsetHeight+'px';
    c.style.left = el.offsetLeft+'px';
    c.style.top = el.offsetTop+'px';
  };
  place(); 
  window.addEventListener('resize', place);
}

你这样称呼它:

cover(myElement, 'black');

示范

有两个限制:

  • 对于某些多行内联块,它不能正常工作
  • 由于它涉及对调整大小事件做出反应的脚本,因此可以通过快速调整大小来临时查看背后的元素
于 2013-04-08T15:43:50.223 回答
0

通常,这是一个看起来要简单得多的问题,但当您开始尝试解决它时就会发现它。我试了一下,虽然它还不是我喜欢的 100%,但我会与你分享我的结果。

首先我应该注意到 jQuery 是完全有效的跨浏览器 JavaScript,所以我想不出任何不使用它的充分理由。当然,如果您从 Google CDN 或类似网站加载它,它可能已经在您的用户缓存中。所以我继续写了一个小的 jQuery 插件(老实说,我的老式 JavaScript 实在是太生疏了)。

首先是代码:

// jQuery plugin to create overlays
// apply to any container that contains DOM elements to be overlayed
$.fn.overlayDiv = function() {
    // remove any old overlays (could be there on resize)
    $(this).find('.overlay').remove();

    // loop trough the remaining children
    $(this).find('*').each(function() {
        // cache some variables
        var $el =  $(this);
        var $parent = $el.parent();

        // make the parent relative, if not yet absolute or fixed, for easy positioning
        if ($parent.css('position') !== 'fixed' && $parent.css('position') !== 'absolute') {
            $parent.css('position', 'relative');            
        }

        // prepare the css
        var css = {};
        css.zIndex = $el.css('z-index');
        css.position = $el.css('position') == 'fixed' ? 'fixed' : 'absolute';
        css.display = 'block';
        // check if inline or block, and calculate settings appropriately
        if ($el.css('display') == 'inline') {
            // -- inline
            // clone the element and render it on one line
            var $clone = $el.clone();
            $clone.css({
                width: 'auto',
                display: 'block',
                whiteSpace: 'nowrap'
            });
            $clone.insertAfter($el);
            // compare height of element and clone
            if ($el.outerHeight(true) == $clone.outerHeight(true)) {
                // if the $el is on a single line
                css.width = $el.outerWidth(true);
                css.height = $el.outerHeight(true);
                css.top = $el.position().top;
                css.left = $el.position().left;  
                // apply the styling to an overlay div and include it in the DOM
                $('<div class="overlay"></div>').css(css).insertAfter($el);
            } else {
                // if the $el is on multiple lines (we need up to 3 divs to overlay)
                // -- this part of the code needs improving --
                var lineHeight = $clone.outerHeight();
                var totalWidth = $clone.outerWidth();
                var lines = $el.outerHeight() / lineHeight;
                var maxWidth = $parent.width();
                // top overlay
                css.width = maxWidth - $el.position().left;
                css.height = lineHeight;
                css.top = $el.position().top;
                css.left = $el.position().left;
                $('<div class="overlay top"></div>').css(css).insertAfter($el);
                // bottom overlay
                css.width = totalWidth - css.width - ((lines-2) * maxWidth);
                css.top = css.top + (lineHeight*lines);
                css.left = 0;
                $('<div class="overlay bottom"></div>').css(css).insertAfter($el);
                // center overlay
                css.width = maxWidth;
                css.height = (lines- 2) * lineHeight;
                // -- /needs improving -- //
            }
            $clone.remove();
        } else {
            // -- block
            css.width = $el.outerWidth(true);
            css.left = $el.position().left;
            // -- height and top might need to improved if you want collapsing margins taken into account
            css.height = $el.outerHeight(true);
            css.top = $el.position().top;
            // apply the styling to an overlay div and include it in the DOM
            $('<div class="overlay"></div>').css(css).insertAfter($el);
        }
    });
}

// when the window is loaded or resized (not just ready, the images need to be there to copy their position and size)
$(window).on('load resize', function() {
    // apply the overlay plugin to the body to cover all elements, or recalculate their positioning
    $('body').overlayDiv();
});

那里有很多评论,所以我认为应该可以理解,但请随时询问您是否需要任何澄清。

你可以在这里看到代码:http: //jsfiddle.net/pP96f/7/

关于剩下的 2 个问题:

  • 最大的问题是跨多行的内联元素。如果您只想覆盖元素内的文本,则最多需要三个单独的叠加层才能实现此目的。我一直在努力解决尺寸问题(尤其是底部 div 的宽度),最终我放弃了。任何输入将不胜感激!
  • 一个较小的问题是边距塌陷。这应该不难解决,但我不确定您希望如何处理。(而且我已经在这个问题上花费了很多时间......)

希望我的意见能对您有所帮助!

编辑:

对于允许您选择要覆盖的特定元素的版本,而不仅仅是选择一个父项并让所有子项(递归地)覆盖,请查看代码的略微更改版本:http://jsfiddle。净/ARWBD/2/

于 2013-04-11T21:43:18.627 回答
0

刚刚在谷歌搜索其他内容时遇到了这个旧线程。

如果您只想突出显示要覆盖的元素并在叠加层中放置一些文本,那么您可以在没有任何 javascript 的情况下执行此操作,只需使用 CSS :after (要覆盖的元素需要 position: relative 虽然)。

div#source {
    position: relative;
}

div#source:after {
    content: "Covered";
    background: purple;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

http://jsfiddle.net/kfdmta7w/

于 2014-12-11T19:35:07.547 回答
0

通过使用 jquery UI position试试这个:

 _overlapTwoElements(topElement, baseElement) {
       if(baseElement.length && topElement.length) {
          topElement.width(baseElement.width());
          topElement.height(baseElement.height());
          topElement.position({ my: "left bottom", at: "left bottom", of: baseElement });
       }
    }
于 2018-08-30T12:44:43.610 回答