Как прокручивать по горизонтали элемент в контейнере, сохраняя его по центру?

У меня есть список элементов в контейнере. Контейнер занимает всю ширину родителя, позволяя элементам переполняться по горизонтали, если это необходимо. Вот как это выглядит:

ul {
  list-style: none;
  display: flex;
  overflow-x: auto;
  padding: 0;
  margin: 0;
  border: 1px dotted black;
}

li {
  margin-right: 10px;
}

li:last-child {
  margin-right: 0;
}

a {
  display: block;
  text-decoration: none;
  white-space: nowrap;
  padding: 4px 8px;
  color: black;
  background-color: white;
  border: 1px solid black;
}

a.active {
  background-color: blue;
}
<ul id = "container">
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#" class = "active" id = "element">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
  <li><a href = "#">Item</a></li>
</ul>

В списке предметов есть тот, который имеет класс .active. Я хочу горизонтально прокручивать контейнер таким образом, чтобы этот элемент был точно по центру. Для этого я написал следующую функцию:

function toMiddle(element, container) {
    if (container === undefined) {
        container = window;
    }
    var elementRect = element.getBoundingClientRect();
    var absoluteElementLeft = elementRect.left;
    var middleDiff = (elementRect.width / 2);
    var scrollLeftOfElement = absoluteElementLeft + middleDiff;
    var scrollX = (scrollLeftOfElement - (container.getBoundingClientRect().width / 2));
    container.scrollTop = 0;
    container.scrollLeft = scrollX;
}

И я пытаюсь вызвать это, чтобы центрировать контейнер следующим образом:

toMiddle(document.getElementById("element"), document.getElementById("container"));

К сожалению, похоже, это не работает должным образом. Любая идея, как я могу это исправить? И что именно я делаю неправильно здесь?

Пожалуйста, обрати внимание, scrollIntoView() работает отлично, но прокручивает всю страницу по вертикали, что неприемлемо для моего варианта использования.

Я попытался запустить ваш код, активный элемент кажется центрированным, как вы и ожидали. scrollIntoView() не делает этот активный элемент центрированным, но вы этого хотите? jsfiddle.net/ucdyhfws

Nick Vu 09.05.2022 05:25
Я не совсем уверен, что вы имеете в виду под:«таким образом, чтобы этот элемент был точно по центру». Вы хотите, чтобы элемент .active был в мертвой точке, когда вы полностью прокрутили страницу?
j D3V 09.05.2022 07:24
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
5
2
124
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете использовать метод .offsetLeft, чтобы найти расстояние слева вместо метода .getBoundingClientRect(). И подсчитайте ширину активного элемента с помощью метода .clientWidth вместо .width, и я также добавил метод .resize для сохранения активного элемента centered.

Полезные ссылки:
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetLeft
https://developer.mozilla.org/en-US/docs/Web/API/Element/clientWidth

function toMiddle(container_id) {
    var container = document.getElementById(container_id);
    var elementRect = document.querySelector('#' + container_id + ' .active');
    var absoluteElementLeft = elementRect.offsetLeft;
    var middleDiff = (elementRect.clientWidth / 2);
    var scrollLeftOfElement = absoluteElementLeft + middleDiff;
    var scrollX = (scrollLeftOfElement - (container.clientWidth / 2));
    container.scrollTop = 0;
    container.scrollLeft = scrollX;
}
/*Initialize on page load*/ 
toMiddle("container");


/*Window resize then active item tab should be centered*/ 
var timeout = 0;
window.onresize = () => {
    clearTimeout(timeout);
    timeout = setTimeout(() => {
        toMiddle("container");
    }, 500)
}

/*Click on item tab then should be centered*/ 
var allItem = [...document.querySelectorAll('#container li a')]
allItem.forEach(element => {
    element.addEventListener('click', (e)=> {
        allItem.forEach(ele => {
            ele.classList.remove('active');
        })
        /*Add active class*/ 
        e.target.classList.add('active');

        /*Call the function for set item tab in centered*/ 
        toMiddle("container");
    })
});
ul {
    list-style: none;
    display: flex;
    overflow-x: auto;
    padding: 10px;
    margin: 0;
    border: 1px dotted black;
    position: relative;
}
li {
    margin-right: 10px;
}
li:last-child {
    margin-right: 0;
}
a {
    display: block;
    text-decoration: none;
    white-space: nowrap;
    padding: 4px 8px;
    color: black;
    background-color: white;
    border: 1px solid black;
    transition: 0.5s ease-in;
}
a.active {
    background-color: #0156e8;
    border: 1px solid #00389a;
    color: #fff;
}
<ul id = "container">
    <li><a href = "#">Item 1</a></li>
    <li><a href = "#">Item 2</a></li>
    <li><a href = "#">Item 3</a></li>
    <li><a href = "#">Item 4</a></li>
    <li><a href = "#">Item 5</a></li>
    <li><a href = "#">Item 6</a></li>
    <li><a href = "#">Item 7</a></li>
    <li><a href = "#">Item 8</a></li>
    <li><a href = "#">Item 9</a></li>
    <li><a href = "#">Item 10</a></li>
    <li><a href = "#">Item 11</a></li>
    <li><a href = "#">Item 12</a></li>
    <li><a href = "#">Item 13</a></li>
    <li><a href = "#">Item 14</a></li>
    <li><a href = "#">Item 15</a></li>
    <li><a href = "#">Item 16</a></li>
    <li><a href = "#">Item 17</a></li>
    <li><a href = "#" class = "active">Item 18</a></li>
    <li><a href = "#">Item 19</a></li>
    <li><a href = "#">Item 20</a></li>
    <li><a href = "#">Item 21</a></li>
    <li><a href = "#">Item 22</a></li>
    <li><a href = "#">Item 23</a></li>
    <li><a href = "#">Item 24</a></li>
    <li><a href = "#">Item 25</a></li>
    <li><a href = "#">Item 26</a></li>
    <li><a href = "#">Item 27</a></li>
    <li><a href = "#">Item 28</a></li>
    <li><a href = "#">Item 29</a></li>
    <li><a href = "#">Item 30</a></li>
    <li><a href = "#">Item 31</a></li>
    <li><a href = "#">Item 32</a></li>
    <li><a href = "#">Item 33</a></li>
</ul>

Я не понимаю, как это центрирует что-либо. Это выглядит так же, как пример ОП.

j D3V 09.05.2022 07:27

Запустите мой фрагмент, чтобы нажать кнопку Выполнить фрагмент кода, чтобы вы увидели вкладку «Элемент 18» по центру. А затем нажмите Полная страница, чтобы вы также поняли, что элемент 18 будет автоматически установлен по центру, или вы также можете проверить, активизировалось ли изменение размера окна Item 18, будет автоматически настроено по центру. А также нажмите «Элемент *», после чего выбранная вкладка «Элемент» будет установлена ​​по центру.

Raeesh Alam 09.05.2022 07:32

Это прекрасно работает, я думаю, что мне не хватило position: relative на <ul>, которое вы добавили. Большое спасибо!

darkhorse 09.05.2022 19:27

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