8

任意の HTML 要素 (画面に表示される) を指定して、別の HTML 要素を作成し、その上に (それを覆うように) スタックする JavaScript 関数を作成することは可能ですか? そして、ページのサイズを変更すると、カバーするコンポーネントとまったく同じように移動します。

(たとえば、getBoundingClientRect を使用していた場合、元のコンポーネントの幅がパーセンテージで表されていると機能しません)

この関数は、要素 (入力内) にマージン、パディング、境界線があるかどうか、表示がブロックかインラインかなど、あらゆるケースを処理する必要があります。

親コンポーネントに対して position: relative を追加してから、「カバー」コンポーネントに position: absolute を作成してみました。パディングやマージンなどのケースを処理しないため、これは機能しませんでした。

注: 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 に答える
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

多くの場合、これは非常に単純に見える問題ですが、実際に取り組み始めてみると、実際にそうなることが判明します。試してみましたが、まだ 100% 気に入ったわけではありませんが、結果を共有します。

まず、jQuery はクロス ブラウザー JavaScript として完全に有効であるため、jQuery を使用しない正当な理由は思いつきません。間違いなく、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 つの問題について:

  • 最大の問題は、複数の行にまたがるインライン要素です。要素内のテキストのみを覆いたい場合は、これを実現するために最大 3 つの個別のオーバーレイが必要になります。私は寸法 (特に下部の div の幅) に苦労していましたが、最終的にはあきらめました。任意の入力をいただければ幸いです。
  • より小さな問題は、マージンの崩壊の 1 つです。これに取り組むのはそれほど難しいことではありませんが、これをどのように処理したいかわかりませんでした。(そして、私はすでにこの質問に多くの時間を費やしています...)

私の意見がお役に立てば幸いです。

編集:

親を選択してすべての子を(再帰的に)オーバーレイするだけでなく、オーバーレイする特定の要素を選択できるバージョンについては、コードのこのわずかに変更されたバージョンを見てください: http://jsfiddle.ネット/ARWBD/2/

于 2013-04-11T21:43:18.627 に答える
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');

デモンストレーション

2 つの制限があります。

  • 一部の複数行のインライン ブロックでは正しく機能しません。
  • サイズ変更イベントに反応するスクリプトが含まれているため、サイズ変更を高速に行うと、背後の要素を一時的に確認できる場合があります。
于 2013-04-08T15:43:50.223 に答える