ilyachalov (ilyachalov) wrote,
ilyachalov
ilyachalov

Category:

JavaScript: заметка рядом с элементом 2

Начало: JavaScript: заметка рядом с элементом.

Решил задачу «Покажите заметку около элемента (абсолютное позиционирование)» к подразделу 1.11 «Координаты» второй части учебника по JavaScript.

В этой задаче предлагается взять решение предыдущей задачи (см. предыдущий пост) и улучшить его.

Сначала разберемся, что не так в обсуждаемом решении. В предыдущем посте мы получили в браузере следующее (картинка, линейные размеры изображения уменьшены в 2 раза):



Тонкая серая линия слева, сверху и справа — это край окна браузера. Я оставил их на картинке, чтобы было видно, где относительно края окна браузера находится текст нашей HTML-страницы.

В задаче предлагается увеличить высоту тела заданной HTML-страницы до 2000px, изменив стиль HTML-элемента body в исходном коде заданной HTML-страницы:
<body style="height: 2000px">
Это должно помочь выявить недостаток решения из предыдущей задачи.

Теперь при просмотре заданной HTML-страницы в браузере получаем следующее (картинка):



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

Теперь сдвинем полосу прокрутки немного вниз (при этом содержимое заданной HTML-страницы будет двигаться вверх). Получается следующее (картинка):



Как видно на иллюстрации, HTML-элемент blockquote (цитата) сдвинулся вверх, а наши три тестовые заметки остались на том же месте относительно левого верхнего угла области просмотра.

Итак, в данной задаче требуется исправить решение из предыдущей задачи так, чтобы при прокрутке содержимого заданной HTML-страницы заметки двигались вместе с HTML-элементом, рядом с которым они изначально были отображены.

Для этого достаточно поменять вид CSS-позиционирования для HTML-элемента, представляющего заметку в нашей задаче. Изначально он установлен в стиле CSS-класса .note (определен в отдельном файле index.css) указанием position: fixed; (то есть HTML-элементы со стилем данного CSS-класса фиксируются на одном и том же месте относительно левого верхнего угла области просмотра в браузере). Если мы поменяем это указание на position: absolute;, то в данном конкретном случае координаты будут отсчитываться от левого верхнего угла HTML-страницы, а не области просмотра в браузере, и будут двигаться вместе с самой HTML-страницей при ее прокрутке.

Указание position: fixed; можно заменить на position: absolute; разными способами. Например, можно подкорректировать исходный код стиля CSS-класса .note в файле index.css. Либо можно изменить это указание из кода функции positionAt на языке JavaScript, например, так:
elem.style.position = "absolute";

Теперь, кажется, всё в порядке. При прокрутке страницы тестовые заметки остаются рядом с HTML-элементом, относительно которого они изначально были позиционированы.

Однако, на самом деле, не всё в порядке. Наш скрипт будет работать правильно, только если при его запуске верхний левый угол области просмотра браузера и верхний левый угол HTML-страницы совпадают (то есть совпадают точки отсчета при определении координат якорного (заданного в параметре anchor нашей функции) HTML-элемента и определении координат тестовых заметок).

Например, чтобы нарушить работу нашего скрипта, достаточно прокрутить немного заданную HTML-страницу и обновить ее (F5). При обновлении HTML-страницы наш скрипт запустится снова, но верхние левые углы области просмотра браузера и самой HTML-страницы при этом уже не будут совпадать, поэтому координаты для заметок будут вычислены неверно.

Чтобы учесть эту ситуацию, следует скорректировать вычисленные координаты, прибавив к ним величину сдвига заданной HTML-страницы. Эти величины хранятся в глобальных переменных pageXOffset и pageYOffset. Тут подробнее:

https://developer.mozilla.org/ru/docs/Web/API/Window/pageYOffset
https://developer.mozilla.org/en-US/docs/Web/API/Window/pageXOffset

Меняем код:
function positionAt(anchor, position, elem) {
    // ... ваш код ...
    let rect = anchor.getBoundingClientRect();      // координаты HTML-элемента anchor
                                                    // относительно области просмотра
    let x = pageXOffset, y = pageYOffset;
    switch (position) {                             // вычислим новые координаты
        case "top":                                 // для HTML-элемента elem
            x += rect.x;                            // относительно HTML-страницы
            y += rect.y - elem.offsetHeight; break;
        case "right":
            x += rect.x + anchor.offsetWidth;
            y += rect.y; break;
        case "bottom":
            x += rect.x;
            y += rect.y + anchor.offsetHeight;
    }
    
    elem.style.position = "absolute";              // исправим вид CSS-позиционирования,
    elem.style.left = x + "px";                    // передвинем HTML-элемент elem
    elem.style.top = y + "px";                     // в новую позицию
}
Красным цветом я отметил исправления. Стоит обратить внимание на замену обычного присвоения = на += в некоторых местах кода. Это исправление можно упустить ненароком.

Теперь, даже если верхние левые углы области просмотра браузера и HTML-страницы не будут совпадать при запуске нашего скрипта, новые координаты заметок всё равно будут вычислены правильно. Это окончательное решение. Решение этой задачи от ее авторов с точки зрения общих принципов такое же, но структурно выполнено по-другому.

Я немного поиграл с заданной HTML-страницей и увидел, что это решение всё еще неидеальное. Область просмотра браузера можно делать шире или уже, меняя ширину окна браузера. При этом текстовый параграф, находящийся выше цитаты (якорного HTML-элемента для тестовых заметок), может менять свою высоту, сдвигая цитату выше или ниже ее первоначального положения. При этом обновления HTML-страницы не происходит и наш скрипт не запускается, то есть заметки остаются на месте, «отрываясь» от требуемых позиций возле якорного HTML-элемента (цитаты). По идее, чтобы учесть и эту ситуацию, запуск нашего скрипта следует выполнять при каждом сужении или расширении окна браузера.
Tags: Образование, Программирование
Subscribe

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments