JQuery смещение возвращает элементы "старой" позиции в IE7 - PullRequest
1 голос
/ 21 декабря 2011

Хорошо, здесь произошла странная ошибка, и до сих пор Google не смог найти ничего, что могло бы с ней справиться.

При использовании IE7 (фактически совместимость с IE8) функция смещения JQuery не возвращает текущее смещение элемента. Вот очень быстрая тестовая страница для демонстрации проблемы:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>

    <script src="Scripts/jquery-1.7.1.js" type="text/javascript"></script>

    <style type="text/css">
        div#Content
        {
            height: 400px;
            overflow: auto;
            border: solid 1px black;
            padding: 2px;
        }
        div.Spacer
        {
            height: 300px;
            border: dotted 1px black;
            background: #ddd;
        }
        div.Wrapper
        {
            padding: 5px;
        }
        div#MoveMe
        {
            position: absolute;
            z-index: 5;
            display: none;
            background-color: Blue;
        }
    </style>
</head>
<body>

    <script type="text/javascript">
        function SetPosition() {
            var divContent = $("div#Content");
            var divMoveMe = $("div#MoveMe");
            var Textbox = $("input#textbox");

            var divMoveMeOffset1 = divMoveMe.offset();

            divMoveMe.css({ "top": "0px", "left": "0px" });
            divMoveMe.height(0);
            divMoveMe.width(0);

            var divMoveMeOffset = divMoveMe.offset();
            var TextboxOffset = Textbox.offset();
            var ContentScrollTop = divContent.scrollTop();
            var ContentScrollLeft = divContent.scrollLeft();
            var divLeft = ((TextboxOffset.left - divMoveMeOffset.left)) + Textbox.outerWidth();
            var divTop = (TextboxOffset.top - divMoveMeOffset.top);
            divMoveMe.css({ "top": divTop + "px", "left": divLeft + "px" });
            divMoveMe.height(Textbox.outerHeight());
            divMoveMe.width(Textbox.outerWidth());

            var divMoveMeOffset2 = divMoveMe.offset();
        }

        $(document).ready(function() {
            $("div#MoveMe").show();
            SetPosition();
            $("div#Content").scroll(SetPosition);
            $(window).scroll(SetPosition);
            $(window).resize(SetPosition);
        });
    </script>

    <div id="Content">
        <div id="Spacer1" class="Spacer">
        </div>
        <div class="Wrapper">
            <input id="textbox" />
            <div id="MoveMe">
            </div>
        </div>
        <div id="Spacer2" class="Spacer">
        </div>
    </div>
    <div id="Spacer3" class="Spacer">
    </div>
</body>
</html>

В IE 8 и Firefox синий div правильно расположен рядом с текстовым полем и удерживает эту относительную позицию посредством прокрутки и т. Д. Однако, когда я возвращаюсь к IE7, он не удерживает позицию правильно.

Насколько я могу судить, функция смещения всегда возвращает значения положения для div в момент вызова функции SetPosition, они не видят изменений, которые должны произойти в результате установки свойств top и left css. Я проверил это, добавив пару дополнительных вызовов в метод смещения и посмотрев на три результата. Все три сообщают об одних и тех же числах смещения, хотя верхняя и левая стороны меняются между вызовами. Кто-нибудь знает способ сделать смещение обновления после изменения свойств CSS? Или альтернативный подход?

Я должен отметить, что это входит в веб-элемент управления, ни одна из разметки или связанных с ней стилей, кроме div Wrapper, не может быть изменена для допустимого решения, на самом деле мне нужно иметь возможность изменять их, не нарушая этого поведение.

ОБНОВЛЕНИЕ: немного поиграв с этим, я заметил, что проблема возникает только тогда, когда функция вызывается во время события прокрутки, вызов во время готовности документа работает правильно.

Ответы [ 2 ]

1 голос
/ 27 декабря 2011

Хорошо, я выяснил, что происходит, если не совсем так, и я смог придумать обходной путь.

В IE 7, если мой метод вызывается из события прокрутки содержимого div, методы jquery position и offset всегда возвращают одинаковые значения в контексте события. Несмотря на то, что элемент перемещается несколько раз, эти методы возвращают значения для позиции, которую он занимал в начале события. Если метод вызывается с помощью других средств, таких как событие готовности документа, кажется, что все работает правильно, и вычисления положения чувствительны к изменяющейся позиции элемента. Я также должен отметить, что откат назад и расчет позиции с использованием стандартного javascript ведут себя так же.

Обходной путь, который я нашел, состоял в том, чтобы разделить мой метод позиционирования на две части, первая часть обнуляет позицию моего div, а вторая часть устанавливает новую позицию. Затем я использую setTimeout в первом методе для вызова второго метода. Это вырывает меня из контекста события, так что мои вычисления положения могут правильно найти нулевую точку деления.

var t;
function SetPosition() {
    var divMoveMe = $("div#MoveMe");
    if (t) {
        clearTimeout(t);
    }

    divMoveMe.css({ "top": "0px", "left": "0px" });
    divMoveMe.height(0);
    divMoveMe.width(0);

    t = setTimeout(function() { SetPosition2(); }, 0);
}
function SetPosition2() {
    var divMoveMe = $("div#MoveMe");
    var Textbox = $("input#textbox");

    var divMoveMeOffset = divMoveMe.offset();
    var TextboxOffset = Textbox.offset();
    var divLeft = ((TextboxOffset.left - divMoveMeOffset.left)) + Textbox.outerWidth();
    var divTop = (TextboxOffset.top - divMoveMeOffset.top);
    divMoveMe.css({ "top": divTop + "px", "left": divLeft + "px" });
    divMoveMe.height(Textbox.outerHeight());
    divMoveMe.width(Textbox.outerWidth());
}

РЕДАКТИРОВАТЬ: Эта версия кода также работает правильно. Похоже, что главное - вырваться из контекста события перед выполнением расчетов позиции.

var t;
function SetPosition() {
    if (t) {
        clearTimeout(t);
    }
    t = setTimeout(function() { SetPosition2(); }, 0);
}
function SetPosition2() {
    var divContent = $("div#Content");
    var divMoveMe = $("div#MoveMe");
    var Textbox = $("input#textbox");

    divMoveMe.css({ "top": "0px", "left": "0px" });
    divMoveMe.height(0);
    divMoveMe.width(0);

    var divMoveMeOffset = divMoveMe.offset();
    var TextboxOffset = Textbox.offset();
    var divLeft = ((TextboxOffset.left - divMoveMeOffset.left)) + Textbox.outerWidth();
    var divTop = (TextboxOffset.top - divMoveMeOffset.top);
    divMoveMe.css({ "top": divTop + "px", "left": divLeft + "px" });
    divMoveMe.height(Textbox.outerHeight());
    divMoveMe.width(Textbox.outerWidth());
}
0 голосов
/ 21 декабря 2011

Ответ на ваш вопрос

jQuerys Offset не возвращает расстояние до окна браузера, но до верхней части документа.

Ваш подход должен бытьвычтите $(window).scrollTop() из $(div).offset().top

Другие советы

Далее я думаю, что эти строки неправильный код ... не совсем уверен.

$("div#Content").scroll(SetPosition);
$(window).scroll(SetPosition);
$(window).resize(SetPosition);

Должно быть вместо SetPosition(), если SetPosition.Но SetPosition нельзя использовать в качестве аргумента без возврата значения?!

Кстати, вы можете использовать:

divMoveMe.css(...).scroll(...).resize(...);

insted of:

divMoveMe.css({ "top": divTop + "px", "left": divLeft + "px" });
divMoveMe.height(Textbox.outerHeight());
divMoveMe.width(Textbox.outerWidth());
...